<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[AndyDangerous]]></title><description><![CDATA[Thoughts, musings, and hopefully, the occasional nugget of wisdom pertaining to explorations of the web &c.]]></description><link>http://andymention.com/</link><generator>Ghost 0.5</generator><lastBuildDate>Tue, 17 Mar 2026 02:20:17 GMT</lastBuildDate><atom:link href="http://andymention.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[How I Git]]></title><description><![CDATA[<p>I'll bet you use git (or Subversion or something, but I know git so that's what I'm writing about). This post may be review for you, but I have opinions and I want to share them on the internet! Jason McCreary wrote some posts about git including this one which sums up <code>git rebase</code> better than I care to. <a href="https://dev.to/gonedark/a-closer-look-at-git-rebase">Check it out.</a> </p>

<h4 id="whydoweusegitwhatproblemarewetryingtosolve">Why do we use git; what problem are we trying to solve?</h4>

<ul>
<li>Revert - You want to be able to confidently undo changes that break your code.</li>
<li>Track changes - You want to be able to figure out what was necessary to implement a feature, or how various code is related to other code. Mostly, you want to know why somebody chose to write a particular piece of code.</li>
</ul>

<p>There are obviously lots of other great features, but these two will suffice for the purposes of this post.</p>

<h4 id="formativemoments">Formative Moments</h4>

<p>I made two very memorable mistakes with git in my first few months as a software developer.</p>

<p>The first related to a feature I had been working on for several days.  I was in the habit of making fairly atomic commits along with WIP (Work In Progress) commits at the end of the day. I'm not sure where my pair was when this went down, but at some point, I ended up merging my branch into master and pushing.  Within half an hour or so, a chat room blew up with questions about merge commits and WIP commits in master.  I was terribly embarrassed, but another developer helped explain what I should have done (squash and rebase).</p>

<p>The second offense was worse. I had pushed code to master that broke something. Upon seeing this, I immediately knew what the problem was and decided to fix it. My solution was to fix the tests and code, <code>amend</code> the commit, and (force) push back to master. This process took maybe five minutes and I figured nobody would be the wiser. Of course the chat quickly blew up again. This time somebody was wondering why they were unable to push to master, having rebased minutes before. Again, I had to identify myself as the culprit.</p>

<p>These were dumb things in retrospect, but you can bet that I learned my lesson. Don't be like me. Follow best practices and your colleagues won't hate you.</p>

<h4 id="somebestpractices">Some best-practices</h4>

<p>Imagine you're working on a feature branch and are ready to submit a PR or however you prefer to submit your code for review.</p>

<ul>
<li><code>rebase</code> to keep your branch up to date. This is helpful to do frequently while working on a branch to ensure you have the latest commits from master. Make sure you do it before creating a PR or merging into master. I almost always complain when I see a PR for a branch that is "3 commits ahead and 30 commits behind" master*.</li>
<li>Squash <em>many</em> of your commits. This one is slightly contentious, but need not be. Remember that the whole point of your commits is to tell a coherent story (and be able to easily revert if something goes wrong). That means that commits destined for master should not have WIP in them and should not include stuff like "fixed more typos." Keep track of that stuff however you want when working on a branch, but squash them before the make it to master.**  I like to squash through an interactive rebase. On the off chance that you do need to revert a commit, having one commit per feature will ensure that you can revert the whole thing without breaking master or dealing with merge commits.</li>
<li>50/72: Message is 50 chars, description wraps at 72 - <a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">Here</a> is one of about a thousand blog posts on why the 50/72 rule of git commits makes sense. Lots of tooling is built around commit messages looking a certain way. It's built into my tooling so I don't even have to think about it. One important side note here is that you should really add comments to commits. There is plenty of room to explain why you made certain choices or any other useful context.</li>
<li>Get your gross merge commits out of my master branch. If you follow the previous points then your PR will be neat and tidy and ahead of master. There is no reason for a merge commit. If you're using Github then you can just "Rebase and Merge" or if you're going cowboy-style then you can just merge your branch into master. Get that: <code>git merge my-branch</code> won't even create a merge commit. It's like git telling you that you're doing it right.</li>
</ul>

<h4 id="finally">Finally</h4>

<blockquote>
  <p>“Code needs to work today just once, but needs to be easy to change forever.”
   -Sandi Metz</p>
</blockquote>

<p>The audience for your git commit history, like your code itself, is your future self and your future colleagues. Make it easy on them. These suggestions may seem petty and annoying at first, but are really pretty easy to get used to. The benefits far outweigh any cost. Alias <code>git blame</code> to <code>git praise</code> if you have to.</p>

<p>* An unnamed collaborator on a project once merged (his own) PR that was in this 3 ahead, 30 behind state. He ended up merging in some commit from weeks before that broke production and was a nightmare to track down. Don't be "him."</p>

<p>** Sometimes people think that they need to track every single commit, change, and dead end as a way of "telling the truth" or preserving context. I argue that a clean commit history (before changes make it to master) tells a better story. If you are worried about preserving context for decisions, then spend some extra time on the commit message and tell that story explicitly.
Now, once a commit <em>is</em> in master then the "telling the truth" argument makes sense.</p>]]></description><link>http://andymention.com/how-to-git/</link><guid isPermaLink="false">85a95a73-73b2-423b-aa4b-cea00d702a19</guid><category><![CDATA[ strongopinions]]></category><category><![CDATA[do-this-not-that]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Fri, 24 Feb 2017 22:01:52 GMT</pubDate></item><item><title><![CDATA[How To Remote]]></title><description><![CDATA[<p>Working with a remote team has many advantages*. It can also be hard to do effectively.</p>

<p>* This post is <em>how</em> to remote. As for why, maybe I'll cover that in the future.</p>

<h2 id="whyyoushouldlistentome">Why you should listen to me</h2>

<p>I started working at an all remote company two years ago. We have since merged with an onsite ("remote-friendly") company and  later been enveloped by a huge corporation. Each step along the way saw the workplace become less friendly to our remote team. This post covers some of the things I have learned.</p>

<h2 id="complaintsanddifficulties">Complaints and Difficulties</h2>

<p>These are a few issues that often come up as obstacles to effective remote work</p>

<blockquote>
  <p>nobody will do any work</p>
</blockquote>

<p>This is a people problem. You do not need to see your engineering team sitting at their desks to know they are working. If there is an issue with the work they are producing then deal with that. Solve the problem at its root. (Hint: not being in the office likely isn't the root of the problem.)</p>

<blockquote>
  <p>face-to-face is the only way to communicate</p>
  
  <p>I can only have a relationship with people I know "irl"</p>
  
  <p>meetings only work in-person</p>
</blockquote>

<p>These are all fallacious arguments and the tools I outline below will help mitigate them.</p>

<blockquote>
  <p>Can you be Agile?!</p>
</blockquote>

<p><strong>People > Process</strong> - Do not take this as petulance, I truly believe it. Rigid corporate waterfall "Big-A" agile rituals can be shaped to work for remote teams, but maybe this is a good opportunity to investigate how much value they are really adding. :)</p>

<h2 id="tooling">Tooling</h2>

<p>I have opinions about tooling and enumerate them <a href="http://andymention.com/remote-tooling/">here</a>.</p>

<h2 id="remotefirstvsremotefriendly">Remote-First vs. Remote-Friendly</h2>

<p>Remote-first refers to an organization that prioritizes remote employees, relationships, and communication. While all-remote companies are remote-first by default, companies split between an office and remote can still work in a remote-first style by following a few guidelines.</p>

<p>Remote-first companies handle meetings and company-wide communication using the tooling that the remote employees use. This can include slack, skype/hangouts, and (gasp!) email. A meeting split between in-office and remote should have each participant calling in from their own computer, even if people in the office are at desks next to each other. This sets the meeting up for success by giving the same communication tools to everyone in the meeting. You wouldn't encourage half the people at an in-person meeting have a private text message chain; think of this as the remote analog. </p>

<p>Your meeting <em>cannot</em> be a conference room with half the team and then a camera "for the remotes" to call in and watch. That makes the remote team effectively an afterthought and thus contradicts the remote-first ethos. </p>

<p>Remote-first in a mixed environment is difficult as it requires the on-site people to always keep their remote team members in mind. Some in-office conversations lead to involving a colleague because they are easy to find at their desk. With remote team members, these should be brought online to the correct forum for full-team communication. This helps spread context and include insights from the remote team members.</p>

<p>Remote-friendly describes a company with a mostly in-person culture, but some remote employees. Often, some of those employees will have a desk, but work remotely a few days per week. The key difference is in communication and culture. Many of the considerations of remote-first are ignored. As more communication happens in the office, the remote team members start to lose context. This may work for a company that is mostly colocated.</p>

<h2 id="considerations">Considerations:</h2>

<h3 id="beoverlyclearinallthings">Be overly clear in all things</h3>

<p>Communicating (especially in writing) is difficult! As the primary form of communication on remote teams, we must be careful to explain ourselves clearly. Another way to ensure clear communication is to reach out for clarification via video; a few minutes of conversation can quickly clarify miscommunication. Both sides of any communication are responsible for this final clarity and should be empowered to instigate clarification.</p>

<h3 id="trust">Trust</h3>

<p>Working remotely requires trust. Employees need to trust management and management must trust their reports. This applies anywhere, but I've seen trust problems <em>blamed</em> on remote. The key here is opening yourself to the vulnerability of trusting your colleagues and making sure that hire people you trust. If you don't trust somebody to do high-quality work then why is that person working for you? </p>

<p>Trust issues are people problems and not related to process.</p>

<h3 id="conwayslaw">Conway's Law</h3>

<p><a href="https://en.wikipedia.org/wiki/Conway%27s_law">Conway's Law</a> is a thing although it is not limited to remote teams. Take it into account or avoid it at your peril.</p>

<h3 id="onsites">Onsites</h3>

<p>Bring your remote team together periodically. The advice in this post will help with a healthy and productive remote environment, but meeting in person is still a great way to make the team stronger.</p>

<h3 id="happyhour">Happy Hour</h3>

<p>Remote happy hours work. Schedule some time at the end of the day, grab your favorite beverage, and chat with your colleagues. You'll get over the weirdness of drinking a beer by yourself and laughing at your computer because you're <em>not</em> by yourself!</p>

<h2 id="finallyalistofdosanddonts">Finally, a list of Dos and Don'ts</h2>

<h3 id="dos">Dos</h3>

<ul>
<li>encourage (or at least don't stifle) some light-hearted banter in meetings</li>
<li>pair frequently</li>
<li>take an interest in your colleagues' lives</li>
<li>consciously leave room in conversations for people who don't feel comfortable interrupting you</li>
<li>if you're sharing a screen then only share what people need to see (one application window ought to do it)</li>
<li>use your video camera ** </li>
<li>overcommunicate</li>
<li>assume the best about your colleagues' intentions</li>
</ul>

<h3 id="donts">Don'ts</h3>

<ul>
<li>"ghost" by muting both video and audio</li>
<li>assume that somebody "got" your humor/sarcasm/ribbing/subtle undertones</li>
<li>differentiate remote employees with demeaning names like "REMOTE," "TV Land," etc.</li>
<li>treat remote team members differently at all</li>
</ul>

<p>**  I am shy and can sometimes be quiet in conversations. By keeping the video on, I show others that I am engaged. Also, leaving it vid-muted is just rude.</p>

<h2 id="wrapup">Wrapup</h2>

<p>The above-mentioned observations and recommendations can help create an environment where a team can come together comfortably and on even footing. Prescriptions from a blog post will not necessarily apply to your organization, but following the spirit of this post will foster strong remote company culture. The biggest peril of remote work is employees feeling disconnected from each other or left out of the culture and communication in the office. The computer can be a personal shield while reducing your colleagues to pixels; try to explicitly practice empathy with all of your colleagues.</p>]]></description><link>http://andymention.com/how-to-remote/</link><guid isPermaLink="false">e18c8926-8dfc-44ab-b85f-580e91912132</guid><category><![CDATA[theory]]></category><category><![CDATA[do-this-not-that]]></category><category><![CDATA[remote]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Thu, 09 Feb 2017 19:14:35 GMT</pubDate></item><item><title><![CDATA[Breaking Rules -  Part 1: Sandi Metz]]></title><description><![CDATA[<p>Rules are great, and nearly everybody likes to break them so this series will explore how and when it's appropriate to break rules. There is a (trite) philosophy stating  </p>

<blockquote>
  <p>Learn the rules well so you can break them properly</p>
</blockquote>

<p>This post attempts to break down how or when to "properly" break some specific rules.</p>

<p>Sandi Metz has <a href="https://www.youtube.com/watch?v=npOGOmkxuio">four rules</a> (or five or six) for writing Ruby (and Rails) code</p>

<ul>
<li>Classes can be no longer than one hundred lines of code.</li>
<li>Methods can be no longer than five lines of code.</li>
<li>Pass no more than four parameters into a method. Hash options are parameters.</li>
<li>Controllers can instantiate only one object. Therefore, views can only know about one instance variable and views should only send messages to that object (@object.collaborator.value is not allowed).</li>
</ul>

<p>She mentions <a href="http://bikeshed.fm/70">in this podcast</a> that people frequently quote her rules while forgetting the most important one:  </p>

<blockquote>
  <p>The [last] rule is that you can break any of [the others], as long as you can get your pair to agree.</p>
</blockquote>

<p>She goes on:  </p>

<blockquote>
  <p>Why is it that we're such cargo-culters about things?</p>
  
  <p>That's the rule that people forget!</p>
</blockquote>

<p>This is a beautiful reason to break a rule. In writing code, you and your pair are codifying the logic of the domain. The most important thing is to keep that code easy for others to understand and modify as the demands of the domain change. That is why Sandi's rules can be so helpful; they make it harder for you to write complex, difficult-to-understand code. However, these rules do not always apply and there are valid reasons to break them.</p>

<p>Working with a pair or code-reviewer is great because together, the team can write better code. </p>

<p>If you have a strong and empathetic working relationship your pair then you will be able to make good decisions together. These rules are heuristics to prompt discussion about whether a particular choice is "good." As professionals, we must be confident in breaking these rules, but only with good reason: we must convince our pair.</p>

<p>Note: <br>
I mostly write this blog for myself. Writing this post was a lot of fun for me in that I went back and listened to some old podcast episodes, watched the conference talk, and then spent a bunch of time figuring out what I actually wanted to say. I highly recommend checking out the links below. Those people are smarter than me and have great insight. If you come to different or other conclusions then feel free to reach out. I love talking about this stuff!</p>

<ul>
<li><a href="http://www.greaterthancode.com/podcast/008-sandi-metz-and-katrina-owen/">Greater than code episode with Sandi Metz and Katrina Owen</a></li>
<li><a href="https://www.youtube.com/watch?v=npOGOmkxuio">Sandi Metz conference talk re: the rules</a></li>
<li><a href="http://bikeshed.fm/70">Bikeshed episode with Sandi Metz</a></li>
</ul>]]></description><link>http://andymention.com/rules-and-when-to-break-them/</link><guid isPermaLink="false">3acd8f6b-9c5e-40cc-a221-9af2ab9ac431</guid><category><![CDATA[ software]]></category><category><![CDATA[ deep thoughtz]]></category><category><![CDATA[ruby]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Thu, 26 Jan 2017 20:20:03 GMT</pubDate></item><item><title><![CDATA[Introduction to Backcountry Skiing]]></title><description><![CDATA[<p>Those who talk to me in the winter know that I love spending time skiing the backcountry. I've learned enough over the years that I think I can share some useful tips for folks getting into the sport.</p>

<p>This post is aimed at comfortable resort skiers looking to expand their skiing horizons. Most of this applies equally to splitboarding. If you're going to splitboard then my best advice is to practice with your gear a lot. Break the stereotype of everyone waiting on the snowboarder: it can be done!</p>

<h3 id="awordaboutsafety">A Word about Safety</h3>

<p>Backcountry skiing is dangerous. It takes some of the risks of resort skiing (e.g. tearing your ACL), and adds in the difficulty of those issues in the wilderness. The backcountry also introduces/increases the exposure to avalanches. The training and safety equipment I'm about to describe is mandatory and non-negotiable. </p>

<h2 id="avalancheeducation">Avalanche Education</h2>

<h6 id="courses">Courses</h6>

<ul>
<li>If you live on Colorado's Front Range then I can't recommend <a href="http://berthoudpass.org/">Friends of Berthoud Pass</a> enough. I volunteer with them so I <em>should</em> recommend them, but I would anyway. You can go to a <em>free</em> three hour Avalanche Awareness classroom session that will give you the basics how to stay safe in the backcountry. They also run on-snow sessions where you can actually play in the snow! Either way, they are a great resource and an excellent way to get more out of your Level I.</li>
<li>Take a Level I avalanche course. You'll spend time both in the classroom and outside, touring around, digging snow pits, and skiing. Ask lots of questions about snow and avalanches as well as touring in general.</li>
</ul>

<h6 id="books">Books</h6>

<p>If you really want to get the most out of your Level I then do the FOBP class and read some of these books.</p>

<ul>
<li><em><a href="https://www.amazon.com/Staying-Alive-Avalanche-Terrain-Tremper/dp/1594850844">Staying Alive in Avalanche Terrain</a></em>, by Bruce Tremper is my favorite book on Avalanches and Snow Science. It could be a little heavy, but if you like to nerd out on this stuff then you'll be into it. Read this before your Level I, and you'll be well-prepared and able to really take advantage.</li>
<li><em><a href="https://www.amazon.com/Snow-Sense-Evaluating-Avalanche-Hazard/dp/061549935X">Snow Sense</a></em>, by Jill Fredston and Doug Fesler is less physically intimidating(i.e. long), but still packed with great information. A classic, you can't go wrong with this book.</li>
<li><em><a href="https://www.amazon.com/Avalanche-Essentials-System-Safety-Survival/dp/1594857172">Avalanche Essentials</a></em>, also by Bruce Tremper is newer and aimed more at beginners than <em>Staying Alive</em>. I am slightly less familiar with this one, but wouldn't hesitate to recommend it.</li>
</ul>

<h6 id="avalancheforecast">Avalanche Forecast</h6>

<p>In Colorado, we use the Colorado Avalanche Information Center(<a href="http://avalanche.state.co.us/">CAIC</a>). I check this site daily from sometime in October until the snow is isothermal in the spring. It's a great way to stay on top of what the snow is doing and how that changes. </p>

<h2 id="gear">Gear</h2>

<h5 id="avalanchesafetygear">Avalanche Safety Gear</h5>

<p>Beacon, Shovel, and Probe are mandatory for travel in avalanche terrain.</p>

<ul>
<li>Beacon - Get a modern, three-antenna beacon. </li>
<li>Shovel - My partners all use metal-bladed shovels</li>
<li>Probe - Eh, these are pretty straightforward, but one that locks automatically when fully extended is way better than one that requires fiddling</li>
<li>Airbag Pack - These seem to work well although they are still new enough that we lack a lot of good statistics. Unfortuunately they're also pretty expensive.</li>
</ul>

<p>Pro tip: Practice things like quickly deploying your shovel and probe. It sounds silly, but practice is important. Think "slow is fast"</p>

<h5 id="skitouringgear">Ski Touring Gear</h5>

<blockquote class="twitter-tweet" data-conversation="none" data-lang="en"><p lang="en" dir="ltr"><a href="https://twitter.com/amention">@amention</a> And using dukes as a quiver of one sucks both ways</p>&mdash; Mike Bannister (@MikeBannister6) <a href="https://twitter.com/MikeBannister6/status/790632891864584192">October 24, 2016</a></blockquote>  

<script async src="http://platform.twitter.com/widgets.js" charset="utf-8"></script>

<p>As a rule, gear that works well at the resort doesn't work well in the backcountry and vice-versa. This pretty much means buying a whole new setup of boots, bindings, and skis. The good news is that the used market for this stuff has gotten a lot better in the past few years and even new gear has gotten a lot more affordable. Sadly, where to buy backcountry skiing gear is a topic for another time.</p>

<ul>
<li>Skis - This is certainly up to personal preference, btu I'm lazy so I like my skis to be light. A 120 underfoot, full-sidewall ski is sweet at the resort, but I like to keep my backcountry stuff light.</li>
<li>Bindings - Again, some people tour with heavy things, but it's not worth it. Don't get plate-style bindings (e.g. Marker Dukes). You'll be much happier with a dynafit-style. These have two pins at the toe of the boot that lock into special metal fittings on your boots and let you tour without lifting up the entire binding plate and heel on every step.</li>
<li>Boots - Focus on walk mode here. some boots have a walk mode that makes them feel like a running shoe while some seem no different than your plug race boots. Go with the former and be happy. Getting ready for the 2016-2017 winter I'll easily recommend the La Sportiva Spectre/Sparkle boots. There is a new version out, but the old ones would be fine too. These are my go-to wintertime boots because they are light, have a great walk mode, and are reasonably stiff on the descent. Best of all, they're cheaper than a lot of the competition.</li>
<li>Poles - Fixed-length poles are coming back into fashion for touring right now. Use whatever works for you.</li>
<li>Pack - I already mentioned airbag packs. Go with one of those if you can afford it. Otherwise, I like a pack that has good "A-Frame" carry (bascially lets you strap your skis to the sides of the pack) and a special pouch for your avy gear. The pouch makes it easy to make sure that your gear is always in the pack and that you can get it out quickly.</li>
<li>Clothes - Your'e going to get hot touring. In Colorado, I almost always wear softshell pants and jackets because the breath well and I run hot. Make sure you have clothing that works for aerobic exercise as well as skiing down. Get good at adding/dropping layers as necessary.</li>
</ul>

<h2 id="otherresources">Other Resources</h2>

<ul>
<li><a href="http://andymention.com/wildsnow.com">Wildsnow</a> is a great blog covering everything bacountry skiing. Read it.</li>
<li>G3 has <a href="http://www.genuineguidegear.com/g3u">a bunch of great short videos</a> out. Follow their tips and you'll skip a lot of the heartache of a beginner backcountry skier.</li>
</ul>]]></description><link>http://andymention.com/introduction-to-backcountry-skiing/</link><guid isPermaLink="false">55baacda-a87c-4c2f-b08e-45fd9546f63f</guid><category><![CDATA[skiing]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Mon, 24 Oct 2016 18:58:42 GMT</pubDate></item><item><title><![CDATA[Tooling for Remote Work]]></title><description><![CDATA[<p>This post relates to my post on <a href="http://andymention.com/pair-programming/">pairing</a>, but digs into some tooling that will help make your life better. Stay tuned for the next post on how to use some of these tools.</p>

<h4 id="learntousevimtmux">learn to use vim/tmux</h4>

<p>Until something better comes along, learn to use vim and tmux if you want to pair remotely. There is defnitely a steep learning curve so remember to use good pairing practice and support people who are new to the tools. The difficulty of learning is worth it; this combination is instantaneous. If you have used screensharing software in the past then imagine sharing your screen, but not having it be terrible. Instead of trying to send a video of your 27" monitor, you only need to know which characters to put where on the screen. It's blazing-fast and looks good for everybody. Anybody connected to the tmux session can watch or drive the action as if it was on your own computer. Screenhero might be ok in a pinch, but you'll hate life if you try to use it every day.</p>

<h4 id="slackorwhateverchatappyouchoose">slack (or whatever chat app you choose)</h4>

<p>This is how you are going to do much of your communication. Here are a few hints on how to use it:</p>

<ul>
<li>Use the right channels for the right tasks (and create new ones if you need to) keep the cat gifs where they belong and the firefighting channel clear for fighting fires.</li>
<li>Don't <code>@everyone</code> unless you're telling folks to go home for the week. If you have something that has to go to everyone (as opposed to, say, people currently in the channel) use email. </li>
</ul>

<h4 id="videochat">video chat</h4>

<p>It doesn't matter what tool you use, but you should be video chatting frequently. I've had good luck with keeping both google hangouts and Skype on deck in case somebody on the team is having trouble with one source. When remote pairing, I like to have my tmux/vim session on a big monitor and a video chat going somewhere else. It'll often be covered up with a browser or documentation or something, but it is nice to be able to look at your pair when you are talking to them.</p>

<h4 id="email">email</h4>

<p>With all these awesome communication tools, you shouldn't need to email very much! Email can be a great async way to share information that people need to hear. Don't abuse it or emails will just get ignored.</p>

<h4 id="calendar">calendar</h4>

<p>Keep a calendar of when people are going to be available. You should be able to see this from slack, but it is good to know if somebody is out for lunch for an hour or sipping cocktails on a beach and not checking slack this week.</p>

<h4 id="git">Git</h4>

<p>Figure out procedures for source control, socialize them, and follow them.</p>

<ul>
<li>Does every commit need a PR?</li>
<li>Does pairing count as code review? </li>
<li>How do you ensure that PRs don't get stale (who is responsible for merging)?</li>
<li>How do you deal with conflicts?</li>
</ul>

<h4 id="projectmanagementsoftware">project management software</h4>

<p>Agree throughout your company how you're going to use this software. Figure out how stories are created, pulled, discussed, and finished. If acceptance criteria belongs with the story (and it does) then make sure each story has it.</p>]]></description><link>http://andymention.com/remote-tooling/</link><guid isPermaLink="false">170814a6-8539-4f6c-824c-916f467d4538</guid><category><![CDATA[theory]]></category><category><![CDATA[do-this-not-that]]></category><category><![CDATA[remote]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Wed, 13 Apr 2016 23:03:59 GMT</pubDate></item><item><title><![CDATA[Pair Programming]]></title><description><![CDATA[<p>There are a plethora of blog posts about how to Pair Program. Here are a few notes I have made based on my experience pairing full time for the last ~1.5 years.</p>

<p>Look forward to more coming soon about pairing remotely and working remotely!</p>

<h4 id="goslow">go slow</h4>

<p>Pairing is awesome. See, e.g., <a href="https://quickleft.com/blog/to-pair-or-pair-that-is-the-question/">this blog post</a>. It really only works if you both people are truly involved. Oftentimes, this means slowing down on a concept that may be mindless for you, but requires a little bit of time for your pair to grok. Commit to spending that time.</p>

<h4 id="makesuretoswitchoffdrivers">make sure to switch off drivers</h4>

<p>This ought to go without saying, but make sure you remember to do it.</p>

<h4 id="makesurebothpeopleknowwtfisgoingondontsteamroll">make sure both people know wtf is going on (don't steamroll)</h4>

<p>This is the responsibility of the pair, not one individual. If you're not stopping your partner to ask what they are talking about then start. Likewise, make sure to check in frequently with questions like "does this make sense to you" or "do you think this approach is the most effective?"</p>

<h4 id="giveeachotherachancetotrysomethingout">give each other a chance to try something out</h4>

<p>In the "fail early and often" vein, give your pair time to try something out fully. Oftentimes, an idea can be a little difficult to verbally articulate. If one member of the pair needs to write some code to help get an idea out, support them in that. Even if you think/know that this idea will not work, trying an idea that eventually fails gives a better understanding of the overall problem to both members of the pair. Also, if one member doesn't get the chance to try an idea then that person is going to be pissed!</p>

<p>Also, here's a helpful video for more a more advanced technique: </p>

<iframe width="560" height="315" src="https://www.youtube.com/embed/dYBjVTMUQY0" frameborder="0" allowfullscreen></iframe>]]></description><link>http://andymention.com/pair-programming/</link><guid isPermaLink="false">7999221e-7dbb-4a1e-9c65-2d5d50c4bfd6</guid><category><![CDATA[programming]]></category><category><![CDATA[theory]]></category><category><![CDATA[do-this-not-that]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Tue, 12 Apr 2016 23:11:35 GMT</pubDate></item><item><title><![CDATA[Mutable Opinions]]></title><description><![CDATA[<p>Ready for a <a href="http://bobsutton.typepad.com/my_weblog/2006/07/strong_opinions.html">strong opinions, weakly held</a> post? I subscribe to this philosophy as a sort of perscription against dogma. I've also been playing with [the functional language] Elixir recently so you can understand my excitement when I saw the following tweet:</p>

<blockquote class="twitter-tweet" lang="en"><p lang="en" dir="ltr">Hey software devs - as you move into the world of functional programming, make sure your opinions stay mutable.</p>&mdash; Brian P. Hogan (@bphogan) <a href="https://twitter.com/bphogan/status/688005278822879232">January 15, 2016</a></blockquote>  

<script async src="http://platform.twitter.com/widgets.js" charset="utf-8"></script>

<p>Of course I got excited about a response that involved Elixir's immutable state that can be rebound to variables. Not wanting to look like a hack, I did a bit of quick googling and, an hour later, decided to write a quick post*.</p>

<h6 id="immutabilityinelixir">Immutability in Elixir</h6>

<p>(in three bullet points)</p>

<ul>
<li>state is immutable in Elixir (it cannot be changed)</li>
<li>variables often need to change their value</li>
<li>variables can be re-bound without changing the original value (in memory)</li>
</ul>

<h6 id="keepingopinionsmutable">Keeping Opinions Mutable</h6>

<p>Here's the meat of this little thought experiment. Your opinions should always be open. Maybe even <a href="http://freeheelvegan.com/">free</a>. This is the "mutability" of your opinions. Be open to changing them with the right new information. At the same time, your old opinions should also still hold some validity. That's why you held them, and held them so strongly. </p>

<p>The consideration of your opinions should be nuanced enough to account for the situation. Perhaps a given situation will merit taking your old opinion, while a new one will require a new one.</p>

<p>I'm generally a fan of DRY programming, especially in Ruby**. Some code I have write and like in Elixir is not as DRY. </p>

<h6 id="itallcomesbackaround">It all comes back around</h6>

<p>Maybe the takeaway is that the original tweet had it right: enjoy functional programming, but keep those opinions mutable.</p>

<p>*<a href="https://twitter.com/fmanjoo/status/688074565973483520">The twitter had also raised a few questions about the nature of a blog</a> and its <a href="http://blog.codinghorror.com/strong-opinions-weakly-held/">scrutiny</a> today, priming the proverbial pump.</p>

<p>** Speaking of dogma, Rubyists need to chill out on the DRYness thing, but that's for another time.</p>]]></description><link>http://andymention.com/mutable-opinions/</link><guid isPermaLink="false">9bae1e4a-a72d-44a8-bca2-1842e3d76227</guid><category><![CDATA[1000wordtweet]]></category><category><![CDATA[ strongopinions]]></category><category><![CDATA[elixir]]></category><category><![CDATA[telemark]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Fri, 15 Jan 2016 20:50:32 GMT</pubDate></item><item><title><![CDATA[Dockerize a Rails App]]></title><description><![CDATA[<p>Heard lots about <a href="https://www.docker.com/whatisdocker">Docker</a> and you want to try it out? This tutorial will demonstrate one way to get a simple Rails app running in Docker.</p>

<p>You're going to need a linux environment to follow along.  If you're using a Mac I recommend you just follow the <a href="http://andymention.com/treat-yourself-to-a-vm/">directions I wrote about getting set up with Vagrant</a>. That will cover installing Docker and Docker Compose. If you already have a linux environment, you can just install them as follows.</p>

<h3 id="installingdockeranddockercompose">Installing Docker and Docker Compose</h3>

<ul>
<li>Docker - There is pretty good <a href="https://docs.docker.com/installation/ubuntulinux/">documentation on the docker site</a>. Here are the commands I used to install:</li>
</ul>

<pre><code>$ sudo apt-get update &amp;&amp; apt-get install wget
$ wget -qO- https://get.docker.com/ | sh
$ sudo usermod -aG docker vagrant
$ sudo docker run hello-world
</code></pre>

<p>The last command should show you a bunch of things including: Hello from Docker.</p>

<ul>
<li>Docker Compose - This will help us manage multi-container apps. Installation docs are <a href="https://docs.docker.com/compose/install/">here</a> or just copy and paste:</li>
</ul>

<pre><code class="shell">$ sudo -i
$ curl -L https://github.com/docker/compose/releases/download/1.3.3/docker-compose-`uname -s`-`uname -m` &gt; /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
$ exit
</code></pre>

<h3 id="dockerizingyourapp">Dockerizing your app</h3>

<p>Clone your app down first. I'm using a demo rails app called <a href="https://github.com/turingschool-examples/storedom">storedom</a> from the good people at <a href="http://andymention.com/turing.io">Turing</a>.  </p>

<pre><code class="shell">$ git clone git@github.com:turingschool-examples/storedom.git ~/src/storedom
</code></pre>

<p>The problem with that app is that it is using SQLite.  We're going to use PostgreSQL so we can have two Docker containers running and talking to each other. To do that, we'll need to change a few files: <code>database.yml</code>, and the <code>Gemfile</code>  </p>

<pre><code class="yaml">#config/database.yml
development: &amp;default  
  adapter: postgresql
  encoding: unicode
  database: storedom_dev
  pool: 5
  username: postgres
  password:
  host: postgres

test:  
  &lt;&lt;: *default
  database: storedom_test

production:  
  &lt;&lt;: *default
  database: storedom
</code></pre>

<pre><code class="shell">#Gemfile
source 'https://rubygems.org'

gem 'rails', '4.1.4'  
gem 'pg'  
gem 'sass-rails', '~&gt; 4.0.3'  
gem 'uglifier', '&gt;= 1.3.0'  
gem 'coffee-rails', '~&gt; 4.0.0'  
gem 'jquery-rails'  
gem 'turbolinks'  
gem 'jbuilder', '~&gt; 2.0'  
gem 'faker'  
gem 'haml-rails'  
gem 'therubyracer'  
gem 'less-rails-bootstrap'

group :development do  
  gem 'spring'
end

group :development, :test do  
  gem 'capybara'
  gem 'pry', :require =&gt; 'pry'
end  
</code></pre>

<h5 id="dockerfile">Dockerfile</h5>

<p>The <code>Dockerfile</code> is a set of instructions Docker uses to build your container.  You start with a base image and then layer on various commands that will install software, organize directories, etc. The commands are carried out in sequence.</p>

<p>Here is an example that will work for storedom:  </p>

<pre><code class="docker">#Dockerfile
FROM ruby:2.2.0

WORKDIR /usr/src/app/

RUN apt-get update -qq &amp;&amp; apt-get install -y build-essential libpq-dev

RUN curl -o /usr/local/bin/gosu -SL "https://github.com/tianon/gosu/releases/download/1.2/gosu-$(dpkg --print-architecture)" &amp;&amp; chmod +x /usr/local/bin/gosu

COPY Gemfile /usr/src/app/Gemfile  
COPY Gemfile.lock /usr/src/app/Gemfile.lock

RUN bundle install

COPY . /usr/src/app  
# copy our project into the WORKDIR

CMD ["rails", "s"]  
# this is the default command we will run when starting the container*
</code></pre>

<p>Docker has good <a href="http://docs.docker.com/reference/builder/">documentation</a> on building a <code>Dockerfile</code>, but you can see a quick explanation of the commands we are using below:</p>

<h6 id="from"><code>FROM</code></h6>

<p>Our base image is ruby 2.2.0. This is a basic Docker image with Ruby 2.2.0 installed on top of Ubuntu. <a href="https://github.com/docker-library/ruby/tree/master/2.2">It is maintained by Docker.</a> The rest of our commands will build off this starting point. </p>

<h6 id="workdir"><code>WORKDIR</code></h6>

<p>The <code>WORKDIR</code> is the working directory for all the other commands.</p>

<h6 id="run"><code>RUN</code></h6>

<p>The first <code>RUN</code> installs two libraries that we will need. The second installs <a href="https://github.com/tianon/gosu">gosu</a>, a tool we use to avoid permissions hell.</p>

<h6 id="copy"><code>COPY</code></h6>

<p><code>COPY</code> copies files into the container.  We are copying in the <code>Gemfile</code> and <code>Gemfile.lock</code> so that we can install our gems in the container. After they are copied into the container, we <code>RUN</code> <code>bundle install</code> to install all our gems. Then we copy our project into the container.</p>

<h6 id="cmd"><code>CMD</code></h6>

<p>The default command for when the container is started. There are a few acceptable form for <code>CMD</code>. This is the preferred form.</p>

<h4 id="dockercompose">Docker Compose</h4>

<p><a href="https://www.docker.com/docker-compose">Docker Compose</a>, formerly called fig, is a tool that helps manage building, running, and linking Docker containers. It consists of a YAML file that sits in your project directory, called <code>docker-compose.yml</code>, and a CLI.</p>

<p>Below is a <code>docker-compose.yml</code> that we can use to get for this project.  </p>

<pre><code class="yaml">#docker-compose.yml
rails:  
  build: .
  command: bundle exec rails s -p 3000 -b '0.0.0.0'
  volumes:
    - .:/storedom
  ports:
    - "3000:3000"
  links:
    - postgres:postgres

postgres:  
  image: postgres
  ports:
    - "5432"
</code></pre>

<p>So what do those things mean? Luckily, the file is reasonably self-explanitory and well  <a href="https://docs.docker.com/compose/yml/">documented</a>, but we can go into a little detail about what each key does.</p>

<h6 id="containername">Container Name</h6>

<p>This sample app needs two containers running: <code>rails</code> and <code>postgres</code>. The first will run the rails app and the second will run the postgres database. They are defined at the top level of <code>docker-compose.yml</code>, and we can use these friendly names to refer to the containers in the Docker Compose CLI.</p>

<h6 id="build"><code>build</code></h6>

<p><code>build</code> maps to a path to a directory that contains a <code>Dockerfile</code>. We have a <code>Dockerfile</code> in the same directory as the <code>docker-compose.yml</code>, and therefor just use<code>.</code>.</p>

<h6 id="command"><code>command</code></h6>

<p><code>command</code> overrides the default command as defined in the <code>Dockerfile</code>
[ ] check the actual command used in the Dockerfile.  Do we even need to use <code>command</code>?</p>

<h6 id="volumes"><code>volumes</code></h6>

<p><code>volumes</code> mounts a path on the host to a path in the new container.  Here, we are mapping the current directory to the <code>/storedom</code> directory in the container.</p>

<h6 id="ports"><code>ports</code></h6>

<p>Similar to our Vagrant setup, <code>ports</code> maps ports on the host to ports in the container. We're keeping everything on 3000 just to make it all easy. Using a string here isn't mandatory, but is idiomatic.  </p>

<h6 id="links"><code>links</code></h6>

<p>This is one of the really cool parts of Docker Compose. <code>links</code> links containers together; in this case, we are giving our app container, <code>rails</code>, access to our database container <code>postgres</code>.</p>

<h6 id="image"><code>image</code></h6>

<p>Every container in Docker Compose needs either <code>build</code> or <code>image</code>. <code>image</code> will pull down the mapped image.</p>

<h4 id="tyingitalltogether">Tying it all together</h4>

<p>Now, you should have everything you need to run your app in Docker containers. Run <code>$ docker-compose up</code> and Docker Compose will build your containers and run them. Learn more about the Docker Compose CLI in the <a href="https://docs.docker.com/compose/cli/">docs</a>.</p>

<p>Go out and cargo-cult to your heart's content. Get it? Because Docker? And cargo!</p>]]></description><link>http://andymention.com/getting-started-with-docker-compose/</link><guid isPermaLink="false">f2c55267-16da-40d4-97df-f112cefc82a5</guid><category><![CDATA[docker]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Fri, 17 Jul 2015 20:33:05 GMT</pubDate></item><item><title><![CDATA[Treat Yourself to a VM]]></title><description><![CDATA[<p>Maybe you want you run linux on your mac (to <a href="http://andymention.com/getting-started-with-docker-compose/">play with docker</a>, perhaps).  This tutorial will walk you though setup of a <a href="https://www.vagrantup.com/">Vagrant</a> VM. At the end, you'll be able to easily boot and connect to a virtual linux machine and develop ruby on it. We're also going to install docker. This is basically a list of commands without a lot of context.  Sorry!</p>

<h2 id="environmentsetup">environment setup</h2>

<p>These instructions use <a href="https://www.vagrantup.com/">Vagrant</a>.  You can download a <code>.pkg</code> file <a href="https://www.vagrantup.com/downloads.html">on vagrant's site</a>. Install that, fire up your terminal, <code>mkdir</code> and <code>cd</code> into a new directory and follow along. First:  </p>

<pre><code class="shell">$ vagrant init ubuntu/trusty64
</code></pre>

<p>When it finishes, you will see that your directory has new <code>Vagrantfile</code>.  Open this up and uncomment/modify the line about port forwarding so that it reads something like this:  </p>

<pre><code class="shell">config.vm.network "forwarded_port", guest: 3000, host: 3000  
</code></pre>

<p>That will let you access port 3000 on your vagrant box via port 3000 on the host machine. We're using this port because it is the default for Rails. Fire up your new linux box with <code>vagrant up</code>. This may take a little while because you have to download and set up the linux machine. </p>

<p>Next, we need to get the new environment set up.  That entails:</p>

<ul>
<li>installing requesite programs</li>
<li><a href="https://twitter.com/josh_cheek/status/426170881896103936">getting your own damn dotfiles on the machine</a></li>
<li>cloning down your project</li>
</ul>

<p>There are a bunch of great provisioning tools out there, but that's for another post. I'm going to just go through what I think are some of the basics.</p>

<p>Install <code>vbguest</code> on your copmuter with  </p>

<pre><code class="shell">$ vagrant plugin install vagrant-vbguest
</code></pre>

<p>Now you can ssh in with the <code>vagrant ssh</code> command.</p>

<h4 id="installingprograms">Installing Programs</h4>

<p>You're going to be doing a lot of <code>apt-get</code>ing. Install a necessary Vagrant plugin and update your apt repositories with  </p>

<pre><code class="shell">$ sudo apt-get update
</code></pre>

<p>Then you'll need to install a bunch of other software. I recommend the following:</p>

<ul>
<li>Git - You may want to create new ssh keys for your vagrant box and add them to github. If so then I recommend following their excellent <a href="https://help.github.com/articles/generating-ssh-keys/">help documentation for that purpose</a>.</li>
</ul>

<pre><code class="shell">$ sudo apt-get install git
</code></pre>

<ul>
<li>ruby - We get 1.9.3 for free, but we're going to use something a little more recent. We're going to use <a href="https://github.com/sstephenson/rbenv">rbenv</a> and <a href="https://github.com/sstephenson/ruby-build#readme">ruby-build</a>. You can follow their install instructions. I'll just reproduce the commands here:</li>
</ul>

<pre><code class="shell">$ sudo apt-get install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev libsqlite3-dev
$ git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
$ git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
$ echo 'export PATH="$HOME/.rbenv/bin:$PATH"' &gt;&gt; ~/.bash_profile
$ echo 'eval "$(rbenv init -)"' &gt;&gt; ~/.bash_profile
</code></pre>

<p>At this point you'll need to restart your shell window.  One way to do this is to log out of the vagrant box with <code>logout</code> and then log back in with <code>vagrant ssh</code>. </p>

<p>Then back to installing ruby. You can see a list of available ruby versions with the <code>rbenv install -l</code> command. Actually installing ruby takes a little while so you will have a minute to get up and stretch*.  </p>

<pre><code class="shell">$ rbenv install 2.2.2 # obviously you can use whatever version you would like
</code></pre>

<p>Once that's installed, you can set it to be your global version (used everywhere) with  </p>

<pre><code class="shell">$ rbenv global 2.2.2
</code></pre>

<p>Now you have ruby!</p>

<ul>
<li>Docker - Again, there is <a href="https://docs.docker.com/installation/ubuntulinux/">pretty good documentation</a> on the docker site.  Here are the commands I used to install:</li>
</ul>

<pre><code class="shell">$ sudo apt-get install wget
$ wget -qO- https://get.docker.com/ | sh
$ sudo usermod -aG docker vagrant
$ sudo docker run hello-world
</code></pre>

<p>The last command should show you a bunch of things including: <code>Hello from Docker.</code></p>

<ul>
<li>docker-compose - while we're at it, we will install docker-compose to help manage multi-container apps:</li>
</ul>

<pre><code class="shell">$ sudo -i
$ curl -L https://github.com/docker/compose/releases/download/1.3.1/docker-compose-`uname -s`-`uname -m` &gt; /usr/local/bin/docker-compose
$ chmod +x /usr/local/bin/docker-compose
$ exit
</code></pre>

<h5 id="dotfiles">Dotfiles</h5>

<p>I like vim. If you've been using it all along then that's great. Otherwise, this will be an opportunity.  One great thing about using vim all the time is that you get it for free with our standard ubuntu version and you only need to clone or copy a few files in order to feel at home wherever you find yourself working. Clone or copy them into your new box.</p>

<h5 id="cloneyourproject">Clone Your Project</h5>

<p>The next thing you need is your project. For this demo, I'm using my most-seen and possibly least-favorite project, <a href="https://github.com/turingschool-examples/storedom">storedom</a>.  </p>

<pre><code class="shell">$ git clone git@github.com:turingschool-examples/storedom.git ~/src/storedom
</code></pre>

<h5 id="profit">Profit</h5>

<p>Now take a look at what you have: a linux virtual machine running on your computer that you can use to develop on or do whatever you need.  If you run your migrations then you should be able to run <code>rails s</code> in your vagrant box and hit the app at <a href="http://localhost:3000/">localhost:3000</a> on your host machine. Things are going well!</p>

<p>* If you really want to follow along then you can open a new window, <code>vagrant ssh</code>, cd into <code>/tmp/</code>, figure out what the ruby-build log file is and then <code>tail</code> it. E.g. <code>tail -f ruby-build.20150712002651.320.log</code></p>]]></description><link>http://andymention.com/treat-yourself-to-a-vm/</link><guid isPermaLink="false">7b35274c-3845-4416-b720-31aee74766ac</guid><category><![CDATA[vagrant]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Fri, 17 Jul 2015 19:02:23 GMT</pubDate></item><item><title><![CDATA[New Beginnings]]></title><description><![CDATA[<p>It's a new year and this one holds a bunch of changes for me.* For starters, I'm starting a new job! I'll be working with the development team at <a href="http://andymention.com/www.wellmatchhealth.com">WellMatch</a>.  </p>

<p>I start on Monday, but my new computer arrived this morning.  It's been a while since I set up a dev environment, so here's a quick rundown of the things I did to get it up and running.  I'll update more as I make more changes.</p>

<h6 id="keyboard">Keyboard:</h6>

<ul>
<li>Fix caps lock/ctrl</li>
<li>Fix key repeat speed and delay until repeat</li>
<li>Set up bluetooth keyboard (and caps/ctrl)</li>
<li>Set up bluetooth mouse</li>
<li>Let tab move through all the controls (^+F7)</li>
</ul>

<h6 id="software">Software:</h6>

<ul>
<li>Xcode and developer tools - don't worry, you'll be prompted about this </li>
<li><a href="http://git-scm.com/download/mac">Git</a></li>
<li><a href="https://www.hipchat.com/downloads">hipchat</a></li>
<li><a href="http://iterm2.com/downloads.html">iterm</a></li>
<li><a href="http://www.google.com/chrome/">chrome</a></li>
<li>something for window management. </li>
</ul>

<h6 id="customization">Customization:</h6>

<ul>
<li><a href="http://andymention.com/">dotmatrix</a></li>
<li><a href="https://gist.github.com/AndyDangerous/d78ca82169161bdac55f">bash_profile</a></li>
</ul>

<h6 id="random">Random:</h6>

<ul>
<li>Put dock on the left</li>
<li>Get all the bullshit out of the dock (lol windows messenger)</li>
</ul>

<p>* I don't do resolutions, so I won't resolve to blog more. There are a bunch of drafts I've been working on so <em>maybe</em> I'll do something with those.</p>]]></description><link>http://andymention.com/new-beginnings/</link><guid isPermaLink="false">d21824f0-2352-410f-81e5-174fecc9560b</guid><category><![CDATA[environment]]></category><category><![CDATA[omgresolutions]]></category><category><![CDATA[mac]]></category><category><![CDATA[setup]]></category><category><![CDATA[ newb]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Fri, 09 Jan 2015 19:31:16 GMT</pubDate></item><item><title><![CDATA[COLOBackcountry architecture]]></title><description><![CDATA[<p>This post refers back to <a href="http://andymention.com/an-open-source-map-stack-the-db/">my COLOBackcountry project</a>. The project takes advantage of the standard Rails MVC pattern to serve up some of the content, and relies on an internal API for the rest. The app basically has a few static pages (main/index, about, etc.) and show pages for the individual ski routes. The pages are rendered in the normal way and the map data are pulled in from a GeoJSON API. This gives the app a very modular character which will lend itself to breaking the app down into a service-oriented architecture in the future.</p>

<h5 id="generalarchitectureanddesignconsiderations">General Architecture and Design Considerations</h5>

<p>I spent a fair bit of time thinking about the architecture for this app and getting UX input from others.  In the end, I think that it lends itself to a one page javascript style, but frankly, I don't know enough javascript to feel comfortable implementing this.  </p>

<p>On the other hand, I'm very comfortable building "normal" rails apps so I decided to focus my limited time on integrating all the other new technologies. I look forward to integrating a javascript framework for the front end in the future.</p>

<h6 id="poros">POROs</h6>

<p>This app has only a few controllers and only a few pages. In order to separate concerns, I ended up building several POROs (Plain Old Ruby Objects) for various data processing needs such as geospatial operations.</p>

<p>One problem I came across was where to put these POROs.  On the one hand, they are somewhat akin to models, and on the other, they are their own sort of thing and do not inherit from <code>ActiveRecord::Base</code>. I ended up keeping them in <code>app/models/</code>, but in the future would consider moving them to <code>lib/</code>.  I turned my GPXParser <a href="https://rubygems.org/gems/gpx2geojson">into a gem</a>, despite its measly single class.</p>

<h6 id="indexshow">Index/Show</h6>

<p>I didn't deviate from the vanilla rails actions too much. One place that could have potentially used a bit of a change is the index vs show pages.  If the app used more javascript and AJAX then I think that it might make sense to have only one page to view the various ski routes.  As it turned out, I ended up sticking with the index/show pages because it made my GeoJSON API calls easier to handle.</p>

<h6 id="api">API</h6>

<p>Speaking of that API, I decided to serve up all my spatial data using a GeoJSON API.  The first reason was that I had just learned about them, and with a shiny new hammer, it seemed only right to find some nails. Aside from that, I like the idea of separating out various parts of my app. If, in the future, I were interested in building out more javascript to make things more modern and slidey, then it will be easy to stick with the current API to fetch the ski routes.  This also allowed me to keep my views dumber.</p>

<p>There were a few chalanges around serializing the ski routes into GeoJSON. My solution doesn't seem terribly elegant, but it does work well.  Basically the serializer does a lot of string manipulation, iterating through each point of the polyline. It works, but I would like to figure out a cleaner method, even if that just means adding a layer of abstraction.</p>]]></description><link>http://andymention.com/open-map-stack-part-3/</link><guid isPermaLink="false">8a7929b7-8c5a-48ff-bee6-a7731eb4d08b</guid><category><![CDATA[rails]]></category><category><![CDATA[ skiing]]></category><category><![CDATA[ geo]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Sun, 30 Nov 2014 08:03:52 GMT</pubDate></item><item><title><![CDATA[Wiring up CRUD Actions Between Ember and Rails]]></title><description><![CDATA[<p>This is not fully fleshed-out, but we're using it.</p>

<p>There are some tutorials out there to help you get started with pairing the excellent Ember front end javascript framework with a Rails back end API. It can be a little harder to find a condensed source to help you go beyond simple GET requests.</p>

<p>This tutorial is based off of a project called <a href="http://andymention.com/www.snowcial.pw">Snowcial</a>, and will cover implementing CRUD actions for an existing <code>groups</code> model. You can substitute this with whatever model makes sense for your project. Requirements include a working app* with <code>index</code> and <code>show</code> actions. We will go over adding <code>create</code>, <code>update</code>, and <code>destroy</code>.  I'll also assume that you are comfortable with Ruby and Rails already though you'll only need passing understanding of javascript and Ember. </p>

<p>*App, in this case, means a Rails app providing a JSON API and an Ember front end consuming it. <a href="http://reefpoints.dockyard.com/2014/05/07/building-an-ember-app-with-rails-part-1.html">This set of tutorials</a> from <a href="http://dockyard.com/">Dockyard</a> will get you up to speed.</p>

<h6 id="anoteabouttesting">A note about testing</h6>

<p>Testing should be first and foremost on your mind when thinking about implementing new functionality for your apps. Unfortunately it is outside the scope of this tutorial. Test your apps. Ask for help or advice if you need it.</p>

<h4 id="ember">Ember</h4>

<h5 id="step1routes">Step 1: Routes</h5>

<p>Routes in Ember are not the same as routes in Rails, but they are also not entirely different.  We'll start here.  create a new <code>app/routes/groups/create.js</code> file and add the following.  We are adding a create function for the <code>group</code> model and the action to go along with it.</p>

<pre><code class="javascript">//app/routes/groups/create.js
import Ember from 'ember';

export default Ember.Route.extend({  
  model: function() {
    return this.store.createRecord('group', {
      name: ''
    });
  },

  actions: {
    create: function() {
    var my_model = this.controller.get('model');
    my_model.save();
    this.transitionTo('groups.show', my_model);
    }
  }
});
</code></pre>

<p>Follow suit for the <code>edit</code>, <code>index</code>, and <code>show</code>.  </p>

<pre><code class="language-javascript">//app/routes/groups/edit.js
import Ember from 'ember';

export default Ember.Route.extend({

  actions: {
   submit:  function() {
    var my_model = this.controller.get('model');
    my_model.save();
    this.transitionTo('groups.show', my_model);
    }
  }
});
</code></pre>

<pre><code class="language-javascript">//app/routes/groups/index.js
import Ember from 'ember';

export default Ember.Route.extend({  
  model: function() {
    return this.store.find('group');
  }
});
</code></pre>

<pre><code class="language-javascript">//app/routes/groups/show.js
import Ember from 'ember';

export default Ember.Route.extend({

  actions:{
    delete: function() {
    this.controller.get('model').destroyRecord();
    this.transitionTo('groups.index');
    }
  }
});
</code></pre>

<h5 id="step2templates">Step 2: Templates</h5>

<p>You will need your templates to have forms for your <code>create</code> and <code>edit</code> actions. Ember's magic will help you out. Unfortunately, my editor doesn't have handlebars highlighting.  That's a thing that you'll want unless you're a total masochist or Swiss, in which case you will prefer <a href="http://emblemjs.com/">Emblem</a>.  </p>

<pre><code class="language-javascript">//app/templates/groups/create.hbs
&lt;h4 class="create-new-group"&gt;Create New Group&lt;/h4&gt;

&lt;p&gt;Name:&amp;nbsp;{{input value=name class='group-name'}}&lt;/p&gt;

&lt;p&gt;Description:&amp;nbsp;{{input value=description class='group-description'}}&lt;/p&gt;

&lt;p&gt;&lt;button type='submit' {{action 'create'}} class='commit-group-creation'&gt;Submit&lt;/button&gt;&lt;/p&gt;  
</code></pre>

<pre><code class="language-javascript">//app/templates/groups/edit.hbs
&lt;h4&gt;Edit&lt;/h4&gt;

&lt;p&gt;Name:&amp;nbsp;{{input value=name class='group-name'}}&lt;/p&gt;

&lt;p&gt;Description:&amp;nbsp;{{input value=description class='group-description'}}&lt;/p&gt;

&lt;p&gt;&lt;button type='submit' {{action 'submit'}} class='commit-group-change'&gt;Submit&lt;/button&gt;&lt;/p&gt;  
</code></pre>

<pre><code class="language-javascript">//app/templates/groups/index.hbs
&lt;h3&gt;Groups&lt;/h3&gt;

&lt;table&gt;  
  &lt;thead&gt;
    &lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Trips Taken&lt;/th&gt;
  &lt;/thead&gt;

  &lt;tbody&gt;
    &lt;p&gt;{{#link-to 'groups.create' class="create-group"}}Create{{/link-to}}&lt;/p&gt;

    {{#each}}
      &lt;tr&gt;
        &lt;td&gt;
          {{~#link-to 'groups.show' this}}
          {{name}}{{~/link-to}}&lt;/td&gt;&lt;td&gt;{{trips.length}}&lt;/td&gt;
      &lt;/tr&gt;
    {{/each}}
  &lt;/tbody&gt;
&lt;/table&gt;  
</code></pre>

<pre><code class="language-javascript">//app/templates/groups/show.hbs
&lt;h4&gt;{{name}}&lt;/h4&gt;&amp;nbsp;  
{{link-to 'Edit' 'groups.edit' model class='edit-group'}}
&lt;button {{action 'delete'}} class="delete-group"&gt;Delete&lt;/button&gt;

&lt;h5&gt;Group Description:&lt;/h5&gt;  
&lt;p&gt;{{description}}&lt;/p&gt;

&lt;h5&gt;Trips&lt;/h5&gt;  
&lt;ul&gt;  
  {{#each trips}}
    &lt;li&gt;{{name}}&lt;/li&gt;
  {{/each}}
&lt;/ul&gt;  
</code></pre>

<p>At this point, you may feel the urge to delete <code>app/templates/groups.hbs</code>. Go for it. Or don't. It's basically just another partial that can hold your various <code>groups</code> templates.  </p>

<h5 id="step3routerjs">Step 3: <code>router.js</code></h5>

<p>Lastly, you'll need to add these new routes to your <code>router.js</code>  </p>

<pre><code class="language-javascript">//app/router.js
import Ember from 'ember';  
import config from './config/environment';

var Router = Ember.Router.extend({  
  location: config.locationType
});

Router.map(function() {  
  this.route('demo');
  this.resource('groups', function() {
    this.route('show', {path: ':group_id'});
    this.route('edit', {path: ':group_id/edit'});
    this.route('create', {path: 'create'});
  });
});

export default Router;  
</code></pre>

<h4 id="rails">Rails</h4>

<h5 id="step1serializers">Step 1: Serializers</h5>

<p>If you don't already have a serializer for your model then you'll need to add <code>gem 'active_model_serializers'</code> to your <code>Gemfile</code> and generate a new serializer.  </p>

<pre><code class="language-terminal">$ rails generate serializer group
</code></pre>

<p>The most important part of your serializer is adding the correct attributes.  I have added a bit more to mine because I want some of the associations to come along as part of the JSON.  </p>

<pre><code class="language-ruby">#app/serializers/group_serializer.rb
class GroupSerializer &lt; ActiveModel::Serializer  
  embed :ids, include: true

  attributes :id, :name, :description
  has_many :trips
end  
</code></pre>

<p>*Note that <code>embed</code> is deprecated. </p>

<h5 id="step2csrfconsiderations">Step 2: CSRF Considerations</h5>

<p>Rails has a default protection against <a href="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)">Cross-Site Request Forgery (CSRF)</a> attacks.  While an in-depth analysis of site security is beyond the scope of this tutorial, you can avoid the problem by changing your ApplicationController.  </p>

<pre><code class="language-ruby">#app/controllers/application_controller.rb
class ApplicationController &lt; ActionController::Base  
  protect_from_forgery with: :null_session
end  
</code></pre>

<p>That should get you up and running. If you have questions or comments then sound off below or feel free to reach out on <a href="http://twitter.com/amention">twitter</a> or <a href="http://github.com/AndyDangerous">GitHub</a>.</p>

<iframe width="420" height="315" src="http://www.youtube.com/embed/LYN8BXmb6h4" frameborder="0" allowfullscreen></iframe>]]></description><link>http://andymention.com/hooking-up-crud-actions-between-ember-and-rails/</link><guid isPermaLink="false">5b6b382d-b751-4d79-8f4c-5c18538d2294</guid><category><![CDATA[rails]]></category><category><![CDATA[ember]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Tue, 04 Nov 2014 00:41:35 GMT</pubDate></item><item><title><![CDATA[Adding Google Analytics to your DO-Hosted Ghost Blog]]></title><description><![CDATA[<p>It seems like quite a few folks <a href="http://andymention.com/www.turing.io">I know</a> are blogging with <a href="http://andymention.com/www.ghost.org">Ghost</a> and <a href="http://andymention.com/www.digitalocean.com">Digital Ocean</a>.  I'm doing it too, and I'd advise following our lead. The process is simple which lets you focus on blogging. </p>

<p>If you're going to the trouble of blogging then you're probably interested in tracking your readers.  Google Analytics is a pretty easy way to do that so I'll show you how to get it set up. I'm assuming you already have your blog set up. If you don't then go to <a href="http://andymention.com/www.digitalocean.com/">www.digitalocean.com/</a>  and set up a droplet with Ubuntu and Ghost preinstalled.</p>

<h6 id="step1">Step 1</h6>

<p>Get an account.  Go to <a href="http://andymention.com/google.com/analytics">google.com/analytics</a> and set yourself up with an account.  Go to admin > tracking info > tracking code. That code will send your tracking information to Google.</p>

<h6 id="step2">Step 2</h6>

<p>ssh into your droplet by typing  </p>

<pre><code class="terminal">$ ssh root@162.243.131.156
</code></pre>

<p>Change my blog's IP address with your own and use another username if you have one.  </p>

<h6 id="step3">Step 3</h6>

<p>Next, you'll need to edit one of the ghost files using the text editor of your choice. I recommend <a href="http://andymention.com/choosing-vim-why/">vim</a>, and that's what I'll use in this example.  You could also use nano. At any rate, open your ghost <code>default.hbs</code>. The directory for this file will depend on your theme.  The default is casper, so that's the path I've given.</p>

<pre><code class="terminal ">$ vim /var/www/ghost/content/themes/casper/default.hbs
</code></pre>

<p>Now you can paste the tracking code from Step 1 into <code>default.hbs</code> I chose to do so right above the <code>&lt;/head&gt;</code> tag. This will render the script on every page.</p>

<pre><code class="html">...
   {{ghost_head}}
  &lt;script&gt;
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', 'YOUR TRACKING ID', 'auto');
    ga('send', 'pageview');
  &lt;/script&gt;
&lt;/head&gt;  
</code></pre>

<p>Save and close the file (<code>:wq</code> in vim).</p>

<h6 id="step4">Step 4</h6>

<p>You'll need to restart Ghost for the change to take effect.  </p>

<pre><code class="terminal">$ service ghost restart
</code></pre>

<h6 id="step5">Step 5</h6>

<p>You should now have your Google Analytics set up, but there's another pro-move you can make. Right now, you do all your blog editing by visiting <code>yourblog.com/ghost</code>. Unless you're wildly popular, all your editing will skew your analytics. We can fix this problem by setting up a filter in Google Analytics to exclude traffic to the admin side of your site. </p>

<ul>
<li>Go back to your Google Analytics dashboard and click on Admin.</li>
<li>Click <strong>All Filters</strong> in the <strong>Account</strong> column.</li>
<li>Click <strong>+ New Filter</strong></li>
<li>Give your new filter a name (e.g. 'exclude blog editing')</li>
<li>Choose Filter Type: Predefined, Exclude, traffic to the subdirectories, that begin with</li>
<li>Fill in the Subdirectory field with <code>/ghost</code> </li>
<li>Add your site to the Selected Views</li>
<li>Click Save
<img src="http://andymention.com/content/images/2014/11/Screen-Shot-2014-11-01-at-2-36-09-PM.png" alt="exclude filter"></li>
</ul>

<p>Now you're really done!</p>

<p>Also, I'm interested in checking out <a href="http://piwik.org/">Piwik</a>, a self-hosted open source analytics platform. That one may be phase two.</p>]]></description><link>http://andymention.com/adding-google-analytics-to-your-do-hosted-ghost-blog/</link><guid isPermaLink="false">945323ae-be53-45e0-a3fb-053abb81d4b1</guid><category><![CDATA[meta]]></category><category><![CDATA[ghost]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Sun, 02 Nov 2014 15:58:15 GMT</pubDate></item><item><title><![CDATA[Choosing Vim: How]]></title><description><![CDATA[<p>Here's a scary post for Halloween!</p>

<p>As I <a href="http://andymention.com/choosing-vim-why">previously mentioned</a>, I'm in the process of getting into Vim.  Here's how:</p>

<blockquote class="twitter-tweet" lang="en"><p>These devs, they come at you all &quot;Hey. Hey kid… use my dotfiles&quot;</p>&mdash; Josh Cheek (@josh_cheek) <a href="https://twitter.com/josh_cheek/status/426170881896103936">January 23, 2014</a></blockquote>  

<script async src="http://platform.twitter.com/widgets.js" charset="utf-8"></script>

<p>I talked to a <a href="http://willfaurot.com/">friend</a> who helped me out by sharing a bunch of recommendations for getting started with Vim. While there are a load of vim plugins out there, I think it is worth adding them one or a few at a time. There is utility in understanding vanilla vim. For example, it's already there on every computer, and better than nano. When you've ssh'd into your VPS and need to make changes, the ability to get around in vim will come in handy. (<code>:E</code>, for example, is a passable replacement for NERDTree) Also, it is overwhelming and unproductive to have too many plugins for software you are trying to learn. </p>

<p>My setup consists of <a href="https://github.com/tpope/vim-pathogen">pathogen</a> along with the following plugins <code>.vimrc</code>.</p>

<p><a href="https://github.com/kien/ctrlp.vim">https://github.com/kien/ctrlp.vim</a> <br>
<a href="https://github.com/terryma/vim-multiple-cursors">https://github.com/terryma/vim-multiple-cursors</a> <br>
<a href="https://github.com/scrooloose/syntastic">https://github.com/scrooloose/syntastic</a></p>

<pre><code class="ruby">execute pathogen#infect()

set rtp+=/usr/local/go/misc/vim  
colorscheme railscasts

"" ==========  These come from Mislav (http://mislav.uniqpath.com/2011/12/vim-revisited/)  ==========  
set nocompatible                " choose no compatibility with legacy vi  
syntax enable  
set encoding=utf-8  
set showcmd                     " display incomplete commands  
filetype plugin indent on       " load file type plugins + indentation

"" Whitespace  
set nowrap                      " don't wrap lines  
set tabstop=2 shiftwidth=2      " a tab is two spaces (or set this to 4)  
set expandtab                   " use spaces, not tabs (optional)  
set backspace=indent,eol,start  " backspace through everything in insert mode

"" Searching  
set hlsearch                    " highlight matches  
set incsearch                   " incremental searching

"" ========== NERDTree  ==========  
autocmd bufenter * if (winnr("$") == 1 &amp;&amp; exists("b:NERDTreeType") &amp;&amp; b:NERDTreeType == "primary") | q | endif " close vim if NERDTree is the only open buffer


"" ==========  Josh's shit  ==========  
set nobackup                                        " no backup files  
set nowritebackup                                   " only in case you don't want a backup file while editing  
set noswapfile                                      " no swap files  
set scrolloff=4                                     " adds top/bottom buffer between cursor and window  
set cursorline                                      " colours the line the cursor is on  
set number                                          " line numbers  
nmap &lt;Leader&gt;p orequire "pry"&lt;CR&gt;binding.pry&lt;ESC&gt;;  " pry insertion  
vnoremap . :norm.&lt;CR&gt;                               " in visual mode, "." will for each line, go into normal mode and execute the "."

"" ========== My shit ==========  
imap kj &lt;Esc&gt;

" easier navigation between split windows  
nnoremap &lt;c-j&gt; &lt;c-w&gt;j  
nnoremap &lt;c-k&gt; &lt;c-w&gt;k  
nnoremap &lt;c-h&gt; &lt;c-w&gt;h  
nnoremap &lt;c-l&gt; &lt;c-w&gt;l

" Emacs/Readline keybindings for commandline mode  
" http://tiswww.case.edu/php/chet/readline/readline.html#SEC4  
" many of these taken from vimacs http://www.vim.org/scripts/script.php?script_id=300  
"  
" navigation  
cnoremap &lt;C-a&gt; &lt;Home&gt;  
cnoremap &lt;C-e&gt; &lt;End&gt;  
cnoremap &lt;C-f&gt; &lt;Right&gt;  
cnoremap &lt;C-b&gt; &lt;Left&gt;  
cnoremap &lt;Esc&gt;b &lt;S-Left&gt; " commenting out b/c makes it pause  
cnoremap &lt;Esc&gt;f &lt;S-Right&gt;  
cnoremap &lt;M-b&gt; &lt;S-Left&gt;  
cnoremap &lt;M-f&gt; &lt;S-Right&gt;  
" editing  
cnoremap &lt;M-p&gt; &lt;Up&gt;  
cnoremap &lt;M-n&gt; &lt;Down&gt;  
cnoremap &lt;C-k&gt; &lt;C-f&gt;d$&lt;C-c&gt;&lt;End&gt;  
cnoremap &lt;C-y&gt; &lt;C-r&gt;&lt;C-o&gt;"  
cnoremap &lt;C-d&gt; &lt;Right&gt;&lt;C-h&gt;
</code></pre>]]></description><link>http://andymention.com/choosing-vim-how/</link><guid isPermaLink="false">fac8ea77-724a-429c-9af7-1f8c48aade3f</guid><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Fri, 31 Oct 2014 21:11:39 GMT</pubDate></item><item><title><![CDATA[Choosing Vim: Why]]></title><description><![CDATA[<p>It's the hip <del>new</del> thing to do: Start using vim.</p>

<p><img src="http://upload.wikimedia.org/wikipedia/commons/thumb/9/9f/Vimlogo.svg/200px-Vimlogo.svg.png" alt="Vim"></p>

<p>I've played with a number of text editors in my brief programming experience. First it was Gedit, which I actually like quite a bit. Then I played around with SublimeText for a while. My time at Turing started out with me using Atom, at the time barely out of beta. I even downloaded Textmate. Now I'm trying to move over to Vim.</p>

<p>Let's back up just a little.  Text editors are pretty straight-forward, and I feel like they should mostly just get out of the way.  That's what Gedit did: it was already there on my Ubuntu box and it was pretty easu to just type <code>gedit [file]</code>.  That worked well at the time.  </p>

<p>Then I started doing a little more serious programming. SublimeText is fast. I liked installing a plugin that let me run ruby right in the editor.  The black background looked so legit.</p>

<p>For most of my time at Turing I have used Atom.  It breaks sometimes. I'm upset that I can't use <a href="https://github.com/JoshCheek/seeing_is_believing">seeing is believing</a> because it keeps breaking for me. But I'm getting better at programming and demanding more from my editor.  I can now move around the editor in ways that are meaningful to my productivity.  It's little more than a glimpse right now, but that's what made me decide to jump to Vim.  </p>

<p>I tried vim-mode in Atom for a while, but it mostly served to mess up my undo commands and annoy people pairing with me. Then I started spending a decent amount of time ssh-ing around the VPS that is hosting my current project, and working in Vim was, surprisingly, not that bad. That was a turning point.</p>

<p>I've seen the way an accomplished Vim user flies around the environment.  I'm jealous and I want in.  So I've taken the plunge.  From here on out, I'm making a conscious effort to use Vim close-to-exclusively. I'll let you know how it goes.</p>

<p>For the meat of <em>how</em> I switched, head over to <a href="http://andymention.com/choosing-vim-how/">that post</a>.</p>]]></description><link>http://andymention.com/choosing-vim-why/</link><guid isPermaLink="false">fd7b0678-3704-43e5-b58c-29e9a48a5c39</guid><category><![CDATA[vim]]></category><category><![CDATA[rant]]></category><dc:creator><![CDATA[Andy Mention]]></dc:creator><pubDate>Wed, 29 Oct 2014 23:45:48 GMT</pubDate></item></channel></rss>