MObtvse Demo

Clever tagline.

What would you want to do?
Kudos

July 23, 2014

This afternoon my intern asked me this simple question. She's a new developer, and a friend of hers is working in a fresh codebase, with best practices. Everything is nice, and he can keep the entirety of it in his head. She's working with my team, Support Engineering. We're the front-line bug squashers at our company. We've got a legacy codebase with no tests and brain melting insanity around every bend.

So she asked me which environment I'd want to be working in if I was her. The question, and the answer speak a lot to what it takes to become a great programmer.

What I would want if I was her is simple. I'd want to be working in the new codebase. There's no question. A new codebase is always more enjoyable to work on. But, what I would want is not what I would recommend with 19 years of professional programming experience.

My suggestion was that right now she was in the best place she could be: debugging a bad codebase with good instincts and helpful mentors, and that's why I'm writing this.

I firmly believe that the most important skill you can learn as a programmer is how to debug: how to debug well, and how to debug fast.

New codebases are great, but they're like kittens. One day they're cute and fun, and the next thing you know they've grown into a tom cat who's running around spraying your furniture. It'll be too big to hold it all in your head, and large swaths of it will have been written by other people. Even if you're really lucky, and people have written great tests, and some god has smiled down upon you and granted you the only significant codebase with no bugs, you'll still need to use your debugging skills.

In the typical case you'll need debugging skills to figure out where the problem is, and then what exactly is going wrong. In our mythical perfect codebase you'll need to figure out where a feature is implemented and how it works in order to build on it. There's really very little difference: hunt something down, understand it, make some changes, write some tests, move on.

People with bad-ass debugging skills get things done faster, in any industry.

That's just the start of why our situation is a better one for her than the happy-fun-land her friend is in. New developers haven't experienced pain yet. They've seen the patterns books but they haven't internalized the problems that resulted in those patterns. They won't know what problems those patterns were designed to avoid, so they won't know when they're about to create that problem. I think that even if they were to go read the best pattern book for their situation they wouldn't be able to truly appreciate it because they don't know the classes of problems they've got to deal with.

Debugging a legacy codebase though... If you've got good instincts, or good mentors (preferably both) you'll be able to see all the ways to not do something. You'll encounter things that just feel wrong, and have people who can explain to you why they're wrong, or what piece of the puzzle you're missing. Once you've found the bad, you'll have to figure out how to make it good, and you'll learn about tradeoffs, because professional coders rarely have the luxury of refactoring everything to be the best it could be, especially in crufty old legacy codebases. No, you have to find the balance. You have to figure out what you can do to improve the situation without spending so much time that the other bugs pile up. It's a lesson I'm still learning nearly 20 years in.

When she eventually moves on from her job as a professional bug slayer she may not know the right way to write good code, but she'll definitely know how to not write bad code, how to make code that other people can understand (because she had to wade through so much incomprehensible stuff), and why you don't violate encapsulation.

A year from now her friend will just be starting to experience the consequences of his inexperienced decisions. A year from now she will be ready to tackle anything.


Writing good User Stories
Kudos

February 20, 2014

First, it should be noted that not all stories are "User Stories". For example a developer might be tasked with manually running some script. The Story might simply be "run the fooberry script".

For everything that effects the UI, use a template:

As a < type of user >
I want < to perform some task >
So that < I can achieve some goal >

Note that it's all about what the user wants. This isn't about instructing what change to make to a system. It's about advising implementers on what the desires of the user are.

Sizing, details, content

Now, everyone says user stories should be "testable", and "small", but what does that mean?

Stories should be "Testable"

You've heard it before, but its a horrible way of expressing the intent. In general, a story is not directly testable. A Story is only testable through its Acceptance Criteria.

Acceptance Criteria?

Each Story should have a compliment of Acceptance Criteria which cover every interaction, and outcome of the Story. Think of it this way. If you write code that meets every Acceptance Criteria and nothing else your coding work should be done. You should not need to write anything else in order to satisfy the Product Owner. Furthermore, you should be able to write a unit or functional test for each acceptance criteria. If you find your test is testing multiple aspects of the system then your acceptance criteria is too large in scope.

For example: if you've added a new page to your app one of the acceptance criteria might be "Administrative users will see a link to the new page in the upper nav. on all pages" This acceptance criteria would pass regardless of where the new link appeared in the "upper nav." If the Product Owner cares where it appears then the criteria isn't specific enough. Note that it also specifies what pages it will appear on. Without that you could put it on the "wrong" page and still pass the criteria.

In XP (Extreme Programming) they use a 3"x5" index card to create all their user stories. The story (in template form) goes on the front, and the acceptance criteria go on the back. The rule-of-thumb is that if the acceptance criteria don't fit on the back of the card, then the story is almost guaranteed to be too big.

Story Sizing

How small is too small? A Story is too small if, by itself, it provides no business value, like this: "As an Administrative User I want to have a link to the new page so that I can navigate to it." Unless someone's already created and deployed the new page, it's a link to nowhere. The next question, of course is how big is too big? I'd say it's too big if it can still be decomposed into multiple smaller pieces of deliverable business value.

User Story Decomposition

General Tips

  • Know your users, before you can write a story about what a user wants, you need to know who your users are. Put together, and commonly agreed upon set of user Personas, and use those persona names when writing the "As a... " portion of your user story. E.g. "As an Accounts Manager I want..."
  • Focus on the user, not the product. Keep your stories focused on the user's goals, and helping them to achieve them.
  • Start big, and decompose It's generally much easier to write an "Epoch" level story (one that comprises many units of business value) and break that down into increasingly smaller stories, than it is to start with fine grained stories.
  • Use index cards (to start with at least). The physical limitations of the card really help make it obvious when a story is too large, because you can't fit it, or it's acceptance tests on one side of a card (unless you write in verrry small print, and that's cheating).
  • Acceptance tests should be automatable If you can't automate the acceptance test, it's probably not a good one. They should be very focused, and very precise.

Finding the Github Pull Request for a topic branch
Kudos

December 24, 2013

Finding the Github pull request associated with a branch.

Work on a large enough project, with other people and sooner or later you're going to find some commit, or branch, and want to know what was in the pull request that merged it in. Maybe you want to see what other commits got merged over at the same time. Maybe you want to see what the diff was at that point in time. But, how do you get from a branch name to a pull-request.

The key to solving this is knowing that pull requests are actually branches. They're just... hidden branches. So, first you start tracking them...

Locate the section for your github remote in the .git/config file. It looks like this:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = git@github.com:joyent/node.git

Now add the line fetch = +refs/pull/*/head:refs/remotes/origin/pr/* to this section. Obviously, change the github url to match your project's URL. It ends up looking like this:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = git@github.com:joyent/node.git
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

Now, after a git fetch origin you can say git checkout pr/999 to checkout pull request number 999 as a local branch and diff it, or do pretty-much anything else with it.

Once you've got that set up, it's just a matter of comparing your local topic branch to the other branches in your system to find other branches that point to whatever branch you're interested in.

I use a shell script called git-find-twins which iterates over the known branches (including pull request branches) and finds any whose tree-ish matches that of the current branch. You can find the latest source here in Github.

[Note: My apologies for the disappearing code on the right side in these examples. Just grab the source from the link above.]

#!/bin/sh
# Finds other git branches whose HEADs point to the same 
# treeish as this branch.

# thanks to mockinterface on 
# http://stackoverflow.com/a/20756047/13973
# for showing how to do this.

echo "Looking for branches pointing to: $(git rev-parse HEAD)"
git for-each-ref --format="%(refname)" | \
    xargs -I refname   \
    sh -c '[[ $(git rev-parse HEAD^{tree}) == $(git rev-parse refname^{tree}) ]] && echo refname'
echo "DONE"

Add that to your path, and make it executable then check out the branch you want to find the pull request for, and run your new shell script with git find-twins (note the space) and you'll see output like this.

$ git find-twins
Looking for branches pointing to: cb3c2dcf606a0a26107131697dd37aef53d44aad
refs/heads/9284_vzw_bug_fixtures_without_fixture_types
refs/remotes/origin/9284_vzw_bug_fixtures_without_fixture_types
refs/remotes/origin/pr/530
DONE

That last one is what you want. 530 the number of the pull request, which you can put into an URL to see the pull request. Now, you're probably saying "Yeah, but what URL?" well, one way to get the correct url is to just bring up any other pull request in the current project and change the number in the url. Or you can add this shell script, which I call urlforpr which generates an url for the pull request number in the current repo. It's based on the assumption that "origin" is the Github repo. If it isn't you'll need to tweak what remote it gets its info from. You can find the latest source here on Github

[Note: My apologies for the disappearing code on the right side in this example. Just grab the source from the link above.]

#!/bin/sh
# when run from a git repository, and passed the number 
# for a pull request, it will generate an url for 
# where to find it on Github. This assumes that
# "origin" is pointing to the Github repo.
# This will work with Github Enterprise too.

if [ $# -eq 1 ]; then
    ROOT_URL=$(git config --get remote.origin.url | \
        sed s/.*@// |sed s/\.git// | sed s/\:/\\//)
    PR_NUM=$1
    echo "https://$ROOT_URL/pull/$1"
else
    echo "Please pass in a Pull Request number"
    echo "Note that this should be run within a git repository"
fi

Bonsai Coding
Kudos

December 06, 2013

Writing code is a lot like maintaining a Bonsai Tree. If you stop pruning it it'll stop being a Bonsai and turn into a bush. Little tweaks, frequently aesthetic ones, will help to keep it beautiful and under control. It will still grow in unexpected directions, as other developers make changes, but careful pruning will keep it balanced, and healthy.

What is "careful pruning" then?

Each file is a branch on our tree. The methods, are leaves. We come in to work and start examining one of the branches. Some days we need to encourage it to grow a specific way by adding a feature. Some days we make little snips to correct a bug. But what happens if, upon examining your branch for other reasons, you discover that it's grown into spirals and knots. You can't reach your clippers in to snip the leaves you need. You can't do much of anything without difficulty and frustration, and frankly, it looks like crap. The unexpected spirals and knots need to go.

This, however, is the point where you'll hear other developers saying "No! Don't do that!" They're upset, because your task wasn't related to the knots and spirals. You were just there to trim some leaves. If you go and get rid of the "other" problems then how will they be able to tell where you trimmed?

To abandon the metaphor for a minute, they're concerned that the diffs will be so filled with aesthetic changes that they can't see the changes that were relevant to the bug fix, or feature add. And, they have a point. Being able to look back and understand the changes another developer made is a very valuable tool. But some developers get so obsessed with this idea, or so beaten down by others who are obsessed with it that they say things like this,

"The rule for controlled development is that if the line is not relevant to the fix, you do not modify it. If we want to go through and fix all the lines in our product that are over 80 characters, then we log a bug for it." - A rule you shouldn't follow

This solution will never leave us with a beautiful tree. I don't know of any professional developer who has the time to deal with tickets that are that low priority, and no-one wants to anyway.

If you accept that there is value in making the line / file readable, then you must also accept that there will be change unrelated to any bug fix or feature request. You must also accept, that if those changes get put off for "later" our tree will become a bush, and require so much work that it will be almost unrecognizable the day after the change.

So, how do we balance these two concerns? How do we make readability changes to our code without obscuring the functional changes? My recommendations are as follows.

  1. It should be acceptable for whatever method you're directly trying to enhance or fix to be refactored for readability. Even if you're refactoring a 20 line method, for a one line fix. To do otherwise is like having a child make their bed but leave their clothes and toys strewn about the floor. Don't do a half-assed job. Leave the method better than you found it.
  2. Separate other aesthetic changes out into separate commits. It would be nicer if you could commit the fix, then commit the aesthetic changes, but we frequently need to make the aesthetic changes in order to make the code readable enough to understand it. So, make it readable, but leave it broken. Commit that change. Then fix it and commit that change.

The downside to 2 is that you have to instruct reviewers to review specific commits, rather than the changeset as a whole. So, an alternative is to make the aesthetic changes, create a pull request / request review of your branch to be merged, and then, once that's done create another pull request for the bug fix. I think it's a judgement call, and the appropriate choice depends on the situation.

As per usual, if you've decent test coverage everything becomes much easier. Code reviewing the aesthetic commits can be just a matter of seeing if the tests pass, and giving it a quick glance to make sure the other developer didn't go all crazy-pants with their changes, like changing the indentation style to something no-other files use. You don't have to stop and consider the funcional impact of the changes, because there shouldn't be any. "Yup, still compiles, still passes the tests, looks more readable. Approved!"

Summary

Codebases are like Bonsai Trees. Regular aesthetic changes are as important a part of keeping your codebase healthy as regular refactorings. Some trivial changes to how you commit your work can elimanate the diffing problems that arise when combining fixes / features with aesthetic changes.


The Daily Team Tracker Worksheet
Kudos

August 22, 2013

The Daily Standup Meeting is a core aspect of Agile development. The simplified idea is that you want to start the day with a very quick status check of what everyone's working on, and helps "...to coordinate efforts to resolve difficult and/or time-consuming issues".

But, how do you keep track of the things your minions are working on today and deal with your own tasks, and 400 daily interruptions? For me the answer was to put together the Daily Team Tracker Worksheet.

Daily Team Tracker

The idea is simple. Each morning, as you go through your Daily Standup write down what each person will be working on today. If they expect to complete the task today there's a little checkbox to indicate that. There is, of course, another to indicate it's done, a notes section, a place for emergent tasks, and more.

When 3pm comes around and I'm wondering, "What was Charles working on? Was he expecting to finish that today? Should I be checking in or leaving him alone?" I can check my sheet and see.

It's also good to have prior days sheets because you can easily see that at task that was supposed to be done "today" has been on someone's plate for three days now, enabling you say "Wait, weren't you expecting to finish that two days ago? What's gone awry? Is there anything I can do to help, or any lesson we can take from that?" (It's all about the Kaizen baby). Some of that will, of course, be covered in your stand-up, but sometimes it's good to have that reminder.

There are two versions of this:

  • Daily Team Tracker PDF (for teams of over 3 people).
    • Page 1 is a the 3 person view with section for notes and diagramming.
    • Page 2 has sections for 5 more folks with a mini notes / diagram section
  • Daily Team Tracker PDF 2 Sided (for teams of 3 or less)
    • Page 1 and 2 are the same 3 person view so that you can print it on both sides of a piece of paper and save some trees.
  • Daily Team Tracker OmniGraffle file If anyone out there has OmniGraffle and feels like tweaking the original.

This file is (cc) 2013 K Rhodes ( masukomi.org ) and distributed under the Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License.