Programming sucks.

Peter Welch via Mashable:

Every programmer occasionally, when nobody's home, turns off the lights, pours a glass of scotch, puts on some light German electronica, and opens up a file on their computer. It's a different file for every programmer. Sometimes they wrote it, sometimes they found it and knew they had to save it. They read over the lines, and weep at their beauty, then the tears turn bitter as they remember the rest of the files and the inevitable collapse of all that is good and true in the world.

The truth of this is both sobering and hilarious.

June 06, 2015  ·  Source  ·  Permalink

My git workflow for teams

This is a guide I wrote a couple years ago. I thought it would be useful for those beginning to use Git for themselves or in a team. Sorry for passive voice ;)

Working in branches on the main repo

First, a note about git stash. Only stash when there are code changes that don't need to be committed. Stashes are only stored locally and ignored by the git push command. Stashes stick around until they are popped or cleared (more on this in a moment). They are not a permanent solution for managing work in progress. For WIP, you might want to consider using a personal branch. Let's get started.

Secondly, always run git status before entering any of the steps in this guide. Understand what everything in it means.

On stashing

Stashes are a great way to temporarily store work in progress. Be careful with these commands as they can destructive when used recklessly.

  • git stash removes all changes from working directory and temporarily stores them in a stash.
  • git stash save 'some description' does the same thing, but with a description of your choosing.
  • git stash pop reapplies changes in the most recent stash and then deletes that stash.
  • git stash apply does the same thing but retains the stash.
  • git stash drop deletes the most recent stash
  • git stash list lists all your stashes, numbers them and orders them from newest to oldest.
  • git stash clear permanently deletes all your stashes (tread carefully)

Using pop, apply, drop with a specific stash is simple. Use one of the following commands as necessary. Use git stash list to learn the number of a specific stash before doing so.

$ git stash pop stash@{0}
$ git stash apply stash@{0}
$ git stash drop stash@{0}

I use stashes to manage my work in progress while staying in sync or working with multiple branches. There are more advanced guides on the git stash command. Google it.

Creating new topic branches

Rule #1: Never commit directly to the master branch. It's unsafe and causes problems for other team members. The right way to safely commit work is by creating branches that are focused on a specific topic, feature, bug, or what have you. Creating a branch is pretty simple. Let's first make sure local master is in sync with origin master:

$ git checkout master 
$ git pull 

Git may complain that the working directory isn't clean. I get around this by running:

$ git stash save "Description of my work in progress"

Running the basic git stash command works too. But it will use the last commit message as it's description which may prove unhelpful.

Run those first 2 commands again and now local master should be in sync with origin master. Lets go ahead and create a new branch:

$ git branch feature_xyz
$ git checkout feature_xyz

Those 2 commands create the branch locally and checks it out. Your branch name should be a short 3 to 5 words and describe what your changes will focus on. Now the magic begins. Code is written. Changes are made. Master of domains and all that.

Protip: It is possible to branch and checkout in one command: git checkout -b feature_xyz.

If you have any stashed code, you retrieve it with:

$ git stash pop

Updating, committing to, and pushing to a topic branch

First. origin describes the "remote" version of all git branches, including master.

While in a topic branch, stash any code changes with: git stash and then run the following:

$ git pull origin master

The above command will pull any changes made to origin master and then stage and commit those changes to the topic branch. This is important because the "merge" becomes commit that can be reverted and seen in commit logs. At this point stashes can be popped or applied.

If busy work is preferred, running the following works:

$ git stash <if needed>
$ git checkout master
$ git pull

Then merge the changes:

$ git checkout feature_xyz
$ git merge master

Sometimes conflicts occur after popping/applying a stash or pull changes from origin master. This happens often because hours, days, and weeks are allowed to pass between changes or those changes a large and sweeping and can't be merged automatically. For this reason, always keep any branches in sync with origin master as often as necessary to avoid conflicts.

Conflict resolution basics

There is a wonderfully simple guide on resolving conflicts manually. Read it. But here is the short; Resolve the conflict, stage the changes, commit and push. My personal rule is to keep conflict resolutions as separate commits. Makes reverts a little easier to deal with in the future.

$ git add path/to/conflicted/file
$ git commit -m "Describe what changed here"
$ git push origin feature_xyz

Commit and push all other changes with the following commands:

$ git add path/to/changed/file
$ git commit -m "Describ your changes"
$ git push origin feature_xyz

Protip: Adding each file one by one is great. But the laziness is real, my friends. git add --all will stage everything including untracked files. git commit -am 'Describe your commit' will add and commit only the modified files, leaving untracked files untouched.

Working in forks of the main repo

The workflow for a fork is a little different. All instructions in this section assumes the main repo has been successfully forked, cloned onto your machine and the main repo added as an 'upstream' remote. Don't know how? GitHub has a simple guide on configuring forks.

Updating, committing and pushing code to your fork

The process is almost identical to what was talked about earlier. But instead of origin we use upstream.

$ git pull upstream master

Just like in a branch, it pulls changes from upstream master, stages and commits them to your fork.

$ git merge upstream/master

The next step is to push these merged changes. Otherwise git will complain that your branch is ahead by a number of commits.

$ git commit -am "Merging upstream master"
$ git push origin master

Now we can pop our stash from earlier. Resolve conflicts if there are any and push our work for a pull request later.

$ git stash pop
$ git commit -am "Some work I did"
$ git push origin master

Protip: You can use the branch workflow in your fork.

Conclusion

Rinse and repeat.

May 29, 2015  ·  Permalink

iTunes and Spotify are aligning to compete

Apple and Spotify are on a war path to dominate the digital music space. Both are very fortified in their own successes but each have something to gain from their competitors' respective strongholds.

In the red corner...

iTunes, a juggernaut of the music industry also does a great job of delivering podcasts, music videos, movies, and television. Still, music has always been the essence of iTunes and its ability to remain king has been in question thanks to the onslaught of music streaming services.

Apple is working on expanding iTunes with a music streaming component through its Beats acquisition. Maybe at last I can stop feeling guilty about not using my huge expensive library of iTunes-purchased music.

In the blue corner...

Spotify, a one category service whose popularity is driven by people leaving behind the pay-per-song and pay-per-album model of music consumption. They have been growing veraciously and they've recently expanded their horizons into fitness, videos and podcasts.

Being a long-time Spotify user, I'm thrilled they're adding podcasts to the mix. Despite Marco Arment's superb Overcast app driving my podcast listening, I think Spotify has a lot to gain from it.

What not to expect

Both companies are certainly stretching outside their comfort zones and it's exciting to see. Undoubtedly users will be switching to and fro and how each company manages retention will be extremely critical. Music is laughably cheap to acquire now and merely offering more of it isn't enough.

With that said, I don't expect artists on music streaming services to start jumping ship like Taylor Swift did not so long ago. Spotify is in a very good position as a distribution platform and any artist would be stupid to ignore that.

Apple's strategy is to show up late. They let the market mature and then launch a product that is all the best parts. I expect Apple to be a very aggressive competitor. But I don't expect them dominate in the short term. Spotify will continue to be a reigning champion of music streaming for the foreseeable future.

As always, time will tell. But it sure is exciting to see the fruits of a competitive market.

May 25, 2015  ·  Permalink

Cucumber step definitions with optional arguments

When I am writing cucumber step definitions that pass arguments, not all of those arguments are needed. And I don't want to write a separate step with or without those arguments. The best way to do this is with a non-capturing regex.

Take the following example (in Ruby):

Given /I am logged in as (.+)/ do |user|
  ...
end

What if I don't want to define a user in every scenario? A default user would be great when none are passed. Since the verbiage works without this portion: as (.+), I'm going to do non-capturing regex around it, which looks like the following:

Given /I am logged in(?: as (.+))?/ do |user|
  ...
end

There are 2 capture groups. The first captures the entire string and the second captures the argument I'm trying to pass. I add ?: which defines the first group as non-capturing. The second group remains the same. How I make it optional is by adding a ? (question mark) to the end of the first group.

Now I can hit two birds with one stone like so:

Given I am logged in
Given I am logged in as some_user

Both will match a single step definition. Don't repeat yourself.

May 15, 2015  ·  Permalink