Git Interactive Rebase With Branching

September 23, 2016 Coding

Two things I like to do in Git never get along.

  1. Work on a development branch and then merge changes into master when they're ready to go to production.

  2. Use interactive rebase to keep my repo's history clean.

The problem came when I would merge some code from dev into master, realize I had made a mistake, and then go back to dev to make the change.

I wanted to interactive rebase to combine my original (but not quite right) commit with the change I made to fix my mistake.

But when I did this and then tried to merge that combined commit back into master, it either created a merge conflict–if the same piece of code changed in different ways in each commit–or a merge commit.

Either way, the whole point is to clean up the history, not have to make another garbage commit.

I finally understood was going on after allowing it to happen way too many times.

Usually merging is smooth because I update my dev branch from master before starting new work. So each commit inherits from HEAD on master, and when I merge them back into that branch, it only needs to fast-forward.

But in this situation, after the fast-forward happens, and HEAD is the same for master and dev, I've gone back into my dev branch and gotten rid of that HEAD commit by interactive rebasing.

My dev branch now has no knowledge of the commit that's still HEAD on master, so the new interactively-rebased commit can't possibly inherit from it.

It stands to reason that when I try to merge this new commit into master, Git sees that the paths have diverged, and a merge commit of some kind will be necessary.

Now that I see what is causing the problem, the solution becomes easy.

After interactively rebasing on dev, I switch to master and do a hard reset, rolling back any commits I've made since the last merge.

Another way to explain it is that I'm resetting the master branch so that HEAD becomes the same commit that my rebased commit on dev inherits from. After all, any code that was in those commits is still present on dev, if I haven't changed it in subsequent commits.

Now when I merge from dev into master, the branch can fast-forward again. Of course, I also have to force-push when I want to send my code up to Github, plus if I've already pulled the code down somewhere else, I have to reset the branch there too, if I don't want a merge conflict.

Maybe a lot to worry about for cleaner history, but I think it's worth it. That's a debate for another day.

Anyway, this seems obvious to me now, but that's only because I've been making more of an effort to improve my mental model of how Git operates.

If you need to do that, I highly recommend reading the first few chapters of the Pro Git book. You may find mysterious Git behavior becoming slightly less mysterious.

Another great resource for solving common but oblique Git problems is Oh Shit Git.

Building Dev Teams: A Panel Discussion

September 13, 2016 Business

My friend Sumeet Jain put together a cool panel discussion about building development teams.

A lot of talk about hiring and training developers, and building tech company culture, is trite. Or sometimes it's completely contrarian. Some say you should hire only people you'd want to hang out with. Others say you shouldn't care about hanging out with them at all.

Sumeet wanted to find a middle ground, where there is real debate to be had on what makes teams productive and fun to be on.

Instead of trying to ask questions, he came up with six statements and asked the panelists to respond to them. The idea was to encourage opinions and controversy.

I'll present each statement and summarize my notes from the ensuing arguments. The panelists didn't disagree as much as Sumeet may have hoped, but the format led to a deeper discussion.

Note: anything in quotes is paraphrased, not verbatim.

Statement 1: Reviewing a candidate's GitHub profile is impractical, as no one is going to spend enough time reading their code to get a meaningful impression.

Kevin Berry, the technical crew chief at motorsports startup RaceNote: "I look at GitHub for 30 seconds, give or take. Instead of looking at the code, I try to get a feel for a person's projects and languages."

There are massively diminishing returns to looking at GitHub profiles. While there's an obvious and visible difference between the profiles of a major open source contributor and a recent graduate, it would take an enormous amount of time to parse out differences between two similar candidates.

If GitHub is impractical, what strategies do work for quickly sussing out a candidate's potential?

The highest efficacy comes from the referral, according to Berry. When he hears about a candidate from a trusted source, there's very little vetting he needs to do.

Rod Smith, a partner at the development agency Volano Solutions, was adamant that cover letters, or their equivalents, are much better indicators than code, especially for would-be consultants. (Emails that come with resumes attached are a modern form of the cover letter, he said, and even better is a face-to-face pitch.)

Raw tech ability can be taught to a greater degree than can relational skills. For an agency, where a developer is constantly working with clients to determine requirements and evaluate solutions, an in-person intro or a great email message are better bets than a carefully-crafted GitHub portfolio.

Statement 2: Programming puzzle questions are only useful if the interviewer is thoroughly trained in administering them–often these questions do more harm than good.

Yes. "Tricks are stupid."

That's not to say there is no code-based thinking taking place in their interviews.

Tony Noecker, CTO at hosting startup Flywheel, likes having developers walk through a problem out loud, so he can get a sense of how they think.

Berry went further: he doesn't mind imposing stressful situations on his candidates to see how they'll respond. (After all, every developer will be under fire on the job at one point or another.)

Richart admitted running candidates through the infamous FizzBuzz puzzle, but he emphasized that this is more of a weed-out activity. He stressed that writing code on the spot is never a make-or-break activity.

Smith likes to find out whether candidates can troubleshoot. Although this is a notoriously difficult skill to test in a contrived environment, it's not going to be any easier without some kind of coding exercise.

When in doubt, it's best to assign a small project, resources permitting. Certainly evaluating a custom piece of code will go much further than parsing a GitHub profile.

Richart, with the perspective of the only panelist at an old-guard company, seemed pleased that "reverence is fading" for the programming puzzle.

Statement 3: Quality and clarity of code–including up-to-date documentation, tests, and application setup instructions–have a direct impact on a team's ability to hire, as only the most experienced developers will be able to navigate a poorly maintained and documented codebase.

Here's where some disagreement began to surface. A few panelists thought this statement was oversimplified, yet with a kernel of truth.

For example, as the statement itself implies, the situation is different for experienced and emerging developers. For the former, the expectation is that she'll have no trouble diving into the deep end.

When hiring a junior developer, it's best to show them to clusters of low-hanging fruit in the codebase. Picking off bugs, perhaps, or writing the missing docs and tests for a stable module.

Berry and Noecker, the two startup co-founders, said that the assumptions in this statement are unrealistic. In a fast-moving environment, documentation can be an unaffordable luxury.

However, what you can have is readable code, hopefully, and strong mentorship channels, something that RaceNote and Flywheel are known for.

Berry posed the question, "are lives at stake?" Referring to Richart's Air Force contracting work, he said that for most hustling companies, hiring without "up-to-date documentation, tests, and application setup instructions" is the only way. It's simply too expensive otherwise.

And yet, there is a difference between a codebase that is improving and one that's getting more tangled and indecipherable. Even if your code is "bad", it should at least be getting better, or a company is not doing any favors for new hires.

Statement 4: Most companies that hire only senior developers do so primarily because they don't know how to train people.

Richart and Berry pointed out that while this may be the case, it's doubtful that companies that only hire senior developers know why they do it.

Berry defended the posture, since senior devs are better. Again, though, in his world, he can't only hire them if he's strapped for resources.

Smith advocated a mix of experience, for two reasons. First, there are pitfalls to senior developers, like the risk of overarchitecting and Not Invented Here syndrome.

Second, assuming you hire well, the juniors and mids are up-and-comers, learning from the seniors while making their bones. All else equal, a senior developer who came up through a company's ranks is more valuable than one coming in off the street.

Another practical benefit for small teams is the ability for developers to do more together than they can alone. Two developers are far better than one, according to Berry, although he advised employers hiring their first developer to go for experience. They can find the right junior developer later on.

Statement 5: Assuming cultural fit, it is better to hire a less experienced developer in a couple weeks and train them than it is to leave a position unfilled for 3+ months waiting for a senior dev.

Berry was vociferous on this point, saying that if he knows for sure that he needs a senior dev to solve a specific problem, he's going to wait.

Nobody else felt strongly either way, and it felt as though the junior-senior debate was running out of steam. Certainly this statement was among the more context-dependent. Sometimes a top talent is needed, but sometimes a product must be shipped quickly. Ah, trade-offs.

Statement 6: For any well-educated developer, the specific language or framework needed on the job is not a meaningful hiring criterion.

This was completely uncontroversial for the panelists.

Smith led the way, insisting that attitude and aptitude are the primary characterists of a good hire, and Richart quickly agreed.

Berry suggested that languages are more important for junior developers, using the example of coding boot camp graduates. An Omaha Code School alum is intimately familiar with modern web application stacks, and can quickly contribute to a team needing that type of work.

Such a student, however, might be at a disadvantage at Grumman, where the toolset is wide-ranging. Berry made an interesting point that traditional four-year Computer Science students would do better in that situation.

There was some ensuing discussion on the merits of code schools and universities. All agreed that there are differences between candidates in breadth and depth of knowledge, so seemingly alike hires can require different mentorship approaches.

An employer should not examine candidates in a vacuum, but rather match them with job requirements. Richart might need a Java expert for a particular project, but Noecker may have more room to coach up a lesser-experienced developer with big potential.

Tony went on to say that ultimately the type of work a potential hire is excited about and their desire to move up the ranks is more important than any language or framework they specialize in.

Lessons

  1. Don't rely on indirect or contrived ways (interview exercises, reading code) to evaluate programming skill–talk to someone who has worked on projects with a candidate, or have the candidate work on a project for you.

  2. Context is everything. Do your homework. Know the type of candidate you need to hire.

  3. Have a codebase candidates want to work on. Have people candidates want to work with.

Local and Instance Variables in Ruby with attr_accessor

August 28, 2016 Coding

In most older OOP languages, you have to write your own getters and setters for your object's variables. Ruby allows you to do this, of course, but it also allows you to create methods that are just the name of the variables:


        class ManualAccessors
          def time=(time)
            @time = time
          end
        
          def time
            @time
          end
        end
        

        m = ManualAccessors.new
        => #<ManualAccessors:0x007fea5bb11910>
        m.time = Time.now
        => 2016-08-29 13:06:45 -0500
        m.time
        => 2016-08-29 13:06:45 -0500
        

Ruby gives you a better way. attr_accessor creates a getter and a setter for you:


        class AttrAccessor
          attr_accessor :time
        end
        

        a = AttrAccessor.new
        => #<AttrAccessor:0x007fb7d42fa268>
        a.time = Time.now
        => 2016-08-29 13:08:10 -0500
        a.time
        => 2016-08-29 13:08:10 -0500
        

That's cool.

But there's a simple mistake I've made, easy to avoid now that I understand it, but maybe not so easy before. It occurs when your class gets more complex and you want to use your automatic setter inside the class's other methods.

Be careful with attr_accessor (and attr_writer) inside your class. Just because you have a fancy automatic setter doesn’t mean you can ignore the difference between local and instance variables:


        class InstanceVariablesVsLocalVariables
          attr_accessor :time
        
          def initialize
            self.time = Time.now
            print_time
          end
        
          def set_time_local
            time = Time.now
          end
        
          def set_time_instance
            self.time = Time.now
          end
        
          def print_time
            puts "The time is #{time}."
          end
        end
        

Using self is how you send a message to the instantiated object. And that's all that attr_accessor does: allow your class to respond to a message.


        i = InstanceVariablesVsLocalVariables.new
        The time is 2016-08-28 19:20:58 -0500.
        => #<InstanceVariablesVsLocalVariables:0x007fea5f521f10 @time=2016-08-28 19:20:58 -0500>
        i.set_time_instance
        => 2016-08-28 19:21:35 -0500
        i.print_time
        The time is 2016-08-28 19:21:35 -0500.
        i.set_time_local
        => 2016-08-28 19:21:55 -0500
        i.print_time
        The time is 2016-08-28 19:21:35 -0500.
        

Hello World

July 31, 2016 Writing

Every blog I’ve ever started has died.

Every website. Every fitness regimen. Every scheduling scheme.

This time I’m going to keep it alive. I don’t care if nobody but me ever reads a single word here. I’m doing it for myself. I need to prove to myself that I can.

If you are reading this, however: welcome! It’s for you, too, if you want it to be.

I do wonder what’s different this time. It feels different, sure, but can I explain it?

My problem is that my standards are too high. I’m worried too much about what you think of me. Are my articles getting any traffic? Do they sound stupid?

Anymore, I don’t give a shit. I’ve danced this dance enough times by now that it holds no more drama for me.

I’m 32 years old. As old as I’ve ever been in my life. So here’s where I’m at: I think that everyone who struggles with discipline and energy and meaning reaches a point in their life where they either shit or get off the pot.

I’ve been a ghost in my own life. But a ghost with the power to Lazarate myself. If I don’t do it now, when’s it gonna happen?

Alright then, it feels different this time. What am I going to do different?

Well, I can’t get obsessed with my analytics if I don’t have any analytics. So that’s out.

I’m already thinking about reposting this on Medium or some other platform where someone will stumble into it. (It’s almost guaranteed that one person will randonmly do so.)

If I really want to preserve the possibility (call it the illusion) that nobody will ever read this but me, then platforms are out.

(Yes, I’m still putting it on the web. This is a blog, not a journal. And I think my ideas are worth something, so who am I to withhold them from you?)

I’m not telling anyone in my physical or digital worlds about this thing. Too often I’ve gotten excited at the beginning of a project, only to spew a bunch of garbage about it to other people and leak out all the magic.

This is between me, the Muse, and the god of the Internet.

I’m not setting any posting goals. I don’t need goals. What I need is to do the work. Work for work’s sake is fun. Work for a goal’s sake is work.

It’s time to have fun again.

P.S.

If you found this and read it all the way down here, congrats! You are quite possibly the first non-me person who ever did so. Let’s be friends! Write me a letter?