Honey Darling

I feel good about this

Subversion to Git: A Retrospective

I knew I wanted my company to make the switch from SVN to Git, for a number of reasons:

  • I had been using Git with Github for a while and it felt good.
  • Our workflow with Subversion was dysfunctional in that no one could commit until code was ready for production.
  • We never branched with Subversion, so working together on a project was painful (emailing patches, yikes).
  • Our Subversion server is in the basement, that sometimes floods. We could have lost all that stuff.

Windows

My fellow developers and I live in a Windows environment, which is not impossible to Git-ify, but it’s certainly more challenging than if we were a bunch of bash geeks.

  • When making the switch, I had to be sensitive to how my fellow devs would use GUIs to interact with our repositories.
  • Pulling our Subversion repository down into Git was very slow on Windows, which meant using a Linux virtual machine to get things started.

git svn clone

The first step was to pull the Subversion repository down into a Git repository by running git svn clone. I followed this awesome guide to perform the following:

  1. Retrieve a list of all Subversion committers
  2. Clone the Subversion repository using git svn

I took one look at our Subversion repository and knew right away that I couldn’t use the --stdlayout flag to pull branches, tags, and trunk. Our repository was all over the place, and it had been moved around a lot over the years, which meant that we would lose commits. I decided to just pull down everything and break things out later.

We lost commits

It’s true, any commits that took place before directories were moved within our repository are no longer part of the history of those directories in Git. We made a decision to let those earlier commits go, rather than figure out a way to get them back. We might just run SVN forever in case we really need to go back.

git-svn died of signal 13

Our Subversion repository is 63,000 commits, which Git had to churn through and transform into Git commits. This was a very long churn (way longer on Windows). Eventually, git svn croaked. The good news is that you don’t have to start over when this happens. Performing a git svn fetch will continue where git svn died. I used while ! git svn fetch ; do sleep 1 ; done from [http://stackoverflow.com/a/13246655/2097613] to get further longer, but even this would eventually die. It took about 12 hours to git svn clone 63,000 commits on a Linux VM with four cores.

git svn fetch

When we were ready to make the big switch, I did one last git svn fetch on the repository to get the latest SVN changes before moving to Git. I saw commits pull in and thought everything was great. But wait! Running a git log showed that I was missing the last 100 commits, and there was no way (that I could figure) to get those in. I had to start all over again, with a 12 hour long git svn clone. I’m not sure what happened, but I’m assuming that I did something to disrupt git svn in my experimentation, perhaps when I was playing with converting svn:ignore into .gitignore and then reverting.

git_split

Our Subversion repository was a beast. I used a handy little script to split directories in my Git repository out into their own bare repositories, complete with all the change history. It was this process that made me learn about the difference between bare and working repositories.

The Workflow

I work with about ten developers, most of whom are comfortable in a GUI-based environment. I wanted the switch to Git to be beneficial for everyone, and I wanted to avoid disruption, if at all possible. I gave two presentations in two weeks: an intro to Git, and then a workflow presentation. I wrote up a very long guide, describing every action that anyone might want to take with Git, using EGit (the Subclipse Git counterpart for Eclipse) and TortoiseGit.

In retrospect, I don’t think I could have possibly known what would happen when we flipped the switch. A whole plentitude of issues arose immediately.

  • LF to CRLF conversion: When installing TortoiseGit, some people had chosen different configurations for handling LF to CRLF file conversion. After the switch, we decided to turn off conversion for everyone, which made a ton of dirty files in everyone’s working copies. Fixing this mess was not a piece of cake.
  • Deployment: Our production server is a working copy, so our typical deployment was a matter of looking at differences in Tortoise SVN’s lovely Check for Modifications tool and then updating the files we wanted. With Git, this process turned into a fetch then a diff then a pull, pulling everything of course, all with password prompts.
  • Branching: Although I encouraged people to start branching, it became clear very quickly that branching was not optional. In retrospect, I would have pushed branching sooner in the switch.
  • Dirty working copies: I thought it would be fairly seamless to copy the Git repository over existing working copies so that dirty files could remain dirty, but for everyone who did not have a starting clean repository, there were issues that weren’t easily resolved.
  • Conflicts: I didn’t realize there would be so many conflicts right off the bat. I was not prepared to help my fellow developers get through conflicts in EGit or Tortoise Git. We made some mistakes when resolving conflicts that resulted in accidentally reverting the repository, sending old files back out to production, and generally breaking stuff all over the place.

The Good News

Yes, the switch was challenging, but so, so satisfying. I knew there were reasons to move, but I don’t think I realized how awesome it would be to have our version control in Git.

  • Everyone’s branching! We have branches all over the place!
  • People are committing! There’s no reason not to commit anymore, and this feels great!
  • Bitbucket is excellent. We haven’t been able to scan through code in a browser in a long time and this is extremely convenient. Also, I needed support a couple of times and Bitbucket was responsive and helpful. And one more thing, Bitbucket’s integration with JIRA is SWEET.
  • A deployment tool! Finally, switching to Git and the pain of deployment was enough to get the resources I needed to make a long-time dream, push-button deployment, a reality at my company.

It’s been about three weeks since we moved to Git, and everyone’s gotten into a comfortable flow. It was total chaos for about a week, and then things worked themselves out. I cannot thank my fellow developers enough for their patience and their help. From quickly written file system scripts to mass reverts, from work on the deployment tool to saving me when I felt overwhelmed. I love my job!

Resources

Here’s just about everything from my SVN to Git bookmarks folder:

Firebase Priority and AngularFire

I recently worked through building a sample application using AngularJS and AngularFire (the officially supported AngularJS API for working with Firebase). You can see the results of my experiments here: https://github.com/honeyd/my-points.

Firebase doesn’t have a ton of ways to query data. Essentially, you have three choices:

  1. Design the data structure so that locations represent queried data
  2. After retrieval, filter the results yourself
  3. Use priority

For my example app, I needed a way to pull all items that occurred between two dates. When I retrieve the children of a Firebase location, I can specify some boundaries.

1
2
3
4
5
var ref = new Firebase('https://firebase-url/items');
// explicit data binding (1-way)
$scope.items = angularFireCollection(ref.startAt(1).endAt(10));
// implicit data binding (2-way)
// angularFire(ref.startAt(1).endAt(10), $scope, 'items');

In this example, $scope.items will include all items with a priority between 1 and 10 inclusive.

Unfortunately, using implicit data binding (angularFire()) on a location that represents an array is problematic at the time of this writing. When the location is loaded into your model, priority is not taken into account, and will be removed the first time the data is saved back to Firebase. See issue 116.

So angularFire() is out and angularFireCollection() is in.

The difference between angularFire() and angularFireCollection() is that angularFire() will set up implicit, or 2-way data binding with your AngularJS model, and angularFireCollection() will only be 1-way, but provide a lot more flexibility.

angularfire()

When I associate a location with my model,

1
angularFire(new Firebase('https://firebase-url/items'), $scope, 'items')

any changes I make to that model ($scope.items) will change the Firebase data as well. This is real nice. I can use $scope.items.push({name: 'Sweetness'}) and $scope.items.splice(0, 1) and $scope.items[0].name = 'Awesome' to my heart’s content.

angularFireCollection()

I can assign a Firebase location to any variable I like, but this variable will not be watched for changes and will not modify the Firebase location unless I call the appropriate methods. The good news is that I can use angularFireCollection() to preserve the priority I have already set on an item as well as set a priority when an item is created or updated.

1
2
$scope.items = angularFireCollection(new Firebase('https://firebase-url/items'));
$scope.items.add({name: 'Yes'}).setPriority(1);

The other good news about using angularFireCollection() is that the ordering of items is better than when using angularFire(), but it’s not perfect. See issue 19.

To see these ideas in action, visit my sample app, or http://plnkr.co/edit/3AfFfo, or https://github.com/honeyd/my-points.

I have my eye on the AngularFire repo for updates to the issues referenced in this post. I’ll edit as AngularFire evolves.

Windows: Open a File From the Command Line With Sublime Text 2

As I spend more time on the command line, I find myself seeking out convenience methods for doing things that usually mean a lot of clicking around, especially in a Windows environment. I’m also moving back and forth a bit between a Linux virtual machine and my regular work Windows OS, and I’m wanting certain things to exist in both places.

BTW: I’m running Windows 7 Professional 64-bit. Your mileage may vary.

The Goal:

subl myfile.txt opens myfile.txt in Sublime Text 2 from a Windows command prompt

Step 1: Create a Windows batch file that will run when the command prompt is opened

  • Create a file where ever you like called autorun.bat. I put mine in c:\dev\autorun.bat
  • Open autorun.bat in a text editor and add the following:
1
doskey subl="C:\Program Files\Sublime Text 2\sublime_text.exe" $*

(Replace the path to your Sublime Text executable as necessary.)

  • Save the file

Step 2: Add the autorun.bat file to your registry

  • Open the Registry Editor (Start –> Type ‘regedit’ in the Search programs and files input)
  • Click down into HKEY_CURRENT_USER\Software\Microsoft\Command Processor
  • If an AutoRun value does not exist, create a new one
    • Right-click Command Processor and click New –> String Value
    • Name the new value ‘AutoRun’
    • Right-click the new value and select Modify…
    • Enter the path to your autorun.bat in the Value data field. Mine says ‘c:\dev\autorun.bat’
    • Click OK

Step 3: Try it out

  • Open a new command prompt
  • cd to a directory with a file that can be opened with a text editor
  • Type subl your-file-name.txt
  • Be happy

Resources

Without these helpful resources, none of this would have been possible.

Life Without a Smart Phone

Anyone who has seen my fingernails will attest to the fact that I am a compulsive person. Having a smart phone in my pocket gets along real well with my compulsive tendencies. I check it every few minutes. I’m especially satisfied to feel the vibration or hear the chime that means there is something to look at. I’m looking at my phone at inappropriate times: during dinner, while I’m with my kids, in a meeting, while I’m driving. I try to moderate, putting my phone somewhere inconvenient or turning it off, but I’m still constantly checking for it, going and getting it, thinking about it.

My phone just isn’t important enough to me, really, to spend so much time with it. There are so many other things I’d rather think about!

There are a couple of disadvantages to not having a smart phone that I had to consider.

  • No access to the Internet means I won’t be able to quickly look something up when I’m out and about.
  • I won’t have a way to easily play music in the car when my daughter says “I want kid’s songs!”
  • My phone will not be a media player, so no more podcasts.
  • I won’t be able to take decent photos with my phone, which means either no pictures or carrying around a bulky digital camera.
  • Texting will likely be harder, and receiving photo messages will be small and distorted.

Choosing a phone that is not a smart phone is not very fun. I bought a Motorola Razr on Ebay, but because it was an unlocked phone and not an AT&T phone, picture texts didn’t work at all, so I ended up just using an old phone we had laying around. At least it has a keyboard. That helps.

The first couple of weeks without my beautiful smart phone were pretty hard. I kept feeling for it in my pocket and realizing that it just wasn’t there. I’d pull out my new phone and be immediately disappointed. There’s just nothing to do with it! Especially when there is a lag in my daily life, waiting in line somewhere for example, I notice that I want my smart phone, but then I just stand there instead. I notice all the other people standing around looking at their phone. I never noticed them before because I was one of them. I rode by a bus stop the other day, and of the 10 or so people waiting for the bus, 9 of them were looking at their phone. I’m one part jealous and one part amazed by the fact that most people are just like me.

I’m not taking pictures, I’m not keeping up with Facebook, I’m seeing new emails in the morning when I get to work, I’m not constantly connected, I’m beginning to feel more comfortable in the in-between times, when I’m alone with myself, with nothing to do. Sometimes doing nothing is nice.

Building a Simple Custom Module in Node.js

Writing modular code is one of my very favorite things to do, so it wasn’t long in my adventure with Node.js before I was trying to understand how to build a custom module. I think I’m finally beginning to grasp exactly how custom modules are typically constructed as well as how they are pulled in as dependencies to my Node application.

First, I’ll create an app.js file from which my experiments will run. For now, I’ll leave app.js empty. Side note: app.js is the typical name of the main file of your new Node.js application.

In the same directory as app.js, I’ll create a new JavaScript file called utils.js. This will be my new module. I’ll add two functions to my utils module that I will be using in my Node.js application.

1
2
3
4
5
6
var addHello = function(name) {
  return "Hello " + name;
};
var addGoodbye = function(name) {
  return "Goodbye " + name;
};

Even though my utils module defines two perfectly good functions, these functions are not yet available to my application. In order to bring my utils module into my application, I define a dependency by using the require() function. In my app.js, I’ll add the following:

1
var utils = require('./utils');

Unfortunately, if I try to run console.log(utils.addHello("Honey")); in my app.js, the code will break. The require() function doesn’t just include the code in my module. Instead, it wraps the code in my module up in a closure that then returns anything set to module.exports. In other words, I need to add the functions I created to a special object called module.exports so that requiring my module will return the addHello() and addGoodbye() methods. I can do this my modifying utils.js in a couple of different ways:

1
2
3
4
5
6
7
8
var addHello = function(name) {
  return "Hello " + name;
};
var addGoodbye = function(name) {
  return "Goodbye " + name;
};
module.exports.addHello = addHello;
module.exports.addGoodbye = addGoodbye;

OR through direct assignment:

1
2
3
4
5
6
module.exports.addHello = function(name) {
  return "Hello " + name;
};
module.exports.addGoodbye = function(name) {
  return "Goodbye " + name;
};

Now when I try to use these functions in app.js, everything should work swimmingly.

1
2
3
var utils = require('./utils');
console.log(utils.addHello("Honey"));
//=> Hello Honey

So far so good? Good. There are some other things to be aware of.

module.exports vs. exports

You may notice that sometimes, people will use the variable exports instead of module.exports. In my utils.js, I can replace all my references to module.exports with just exports, and everything will continue to work as expected.

1
2
3
4
5
6
exports.addHello = function(name) {
  return "Hello " + name;
};
exports.addGoodbye = function(name) {
  return "Goodbye " + name;
};

Remember that wrapper I mentioned, that is responsible for packaging the code in my module? Well, before it pulls in my code, it assigns module.exports to exports, so that exports is just a pointer to module.exports. Take a look at this excellent answer from StackOverflow: Difference between “module.exports” and “exports” in the CommonJS Module System.

In other words, exports is a shortcut to module.exports (less typing), but it’s not the variable that is returned, so I have to be careful. As a result of this, I see the following pretty often, especially when a custom module is a constructor:

1
var Book = exports = module.exports = function() {};

That’s a lot of assignment! This statement not only ensures that exports and module.exports are the same, but it also assigns the module function to a variable that can be used for anything I like outside of the constructor function (like adding methods to the prototype, for example).

Interestingly, I can require() a directory, not just a single file. Node.js will gladly look in the directory and see if I have an index.js file to use, and pull that in if it exists. If I wanted to package up a bunch of modules into one require(), I might add something like this to index.js (assuming one.js and two.js exist in the same folder):

1
2
3
4
module.exports = {
  one: require('./one'),
  two: require('./two')
};

Then I can require the directory in app.js (assuming index.js, one.js, and two.js live in a directory called “stuff”):

1
var stuff = require(./stuff);

Looping Over an Array, Beginning at an Offset

I’m playing around with building a little Texas Hold ‘em simulator. I set up the players as an array, and started a hand. I realized pretty quickly that I’ll need to start play at a different player each hand, which means looping over the array with a different offset every time. I wondered, how do I loop over the entire array, beginning at a position other than 0? And then the magical modulus operator came to my rescue.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// set up the array
var fruit = ['banana','apple','orange','kiwi','watermelon'];

// set an offset
var offset = 3;

// loop over the array
for (var i = 0; i < fruit.length; i++) {

  // calculate the iterator
  var it = (i + offset) % fruit.length;

  // access the array element, using the fancy iterator
  console.log(fruit[it]);

}
1
2
3
4
5
kiwi
watermelon
banana
apple
orange

My Dream Development Environment

In my dream development environment, the following would be a reality:

The project manager has a clear and ongoing interpretation of project priority and can assign work accordingly. She maintains a queue of projects, tasks, and bugs for the team as a whole and also for each developer. She clears roadblocks before assigning tasks.

Quarterly:

Every quarter, the project manager presents the project roadmap to the entire development team. She recaps what we have accomplished in the last quarter, and call out the developers who have contributed substantial effort to the company’s priorities and strategic vision. The project manager reviews the projects that are in progress and describe upcoming initiatives. As a result of this meeting, the entire team will have a better idea of where our efforts will be focused not only in the quarter beginning, but also a general look at the year ahead.

Every other week:

Every other Friday, the developers all get together in one room. Each developer has 5 minutes to present the most interesting information regarding their work over the last two weeks. A timer is used to be sure that the meeting stays as short as possible. The project manager has the opportunity to communicate valuable information, including shifting priorities.

Daily:

When I come in to work in the morning, I take a look at my queue to see what I’ll be working on next. It could be project-related, or I might need to fix a high priority bug. I may need to complete a task for a project where I am a primary developer, or I may have to do some work for another project.

I open up the task to see what I’ll be doing. The task is clearly defined, all roadblocks are cleared, and I am able to get started easily and quickly. If the task is a bug, there are supporting screenshots and steps to reproduce the problem. If the task is project related, there is a spec document to consult if I run into unknowns. There is a time or difficulty estimate so I have a general idea of how much time I’ll be spending on this effort. If no estimate was provided, I modify the task to reflect my own.

I open the task through Eclipse and trigger an in-progress event so that the project manager and others can see where I am focused. When I’m finished coding and I have made sure to the best of my ability that the change I have made works as expected, I commit my code. I mark the task as “code complete” through Eclipse. The project manager sees a task to be tested in her queue and oversees validation of the change. She reassigns the task to me to deploy, prioritizing the task in my queue appropriately. If the task is project related, a separate deploy task may be assigned and the smaller tasks can be closed.

If at any point, I realize that a task will take significantly (> 1 hour) longer than the estimate, I will communicate this information to the project manager. We will work together to determine the best course of action. I may need to put the ticket on hold while more important tasks are completed. If I continue working on the task, I will update the estimate to reflect the new value.

The project manager is responsible for most of the communication with support. The project manager is assigned tasks and then creates JIRA (or whatever system we’re using) tickets that are then assigned to me. I only want one task queue to keep track of. When someone finds a bug or has a feature request, they can call, email, or chat with the project manager to review the information if necessary. If the project manager decides that a conversation with a developer is necessary, she sets up a meeting. In an emergency situation, that meeting could be immediate, but this is not ideal. There is a stakeholder defined for each task so that when questions arise during development, I know exactly who I need to talk to, and this person has (or can find) the correct answer. I can call, chat, or email this person, and feel comfortable bringing the project manager into the conversation or not as needed.

The project manager stops by my desk every day for a few minutes to review my tasks. She lets me know if there have been any general priority shifts or feedback regarding changes I’ve made. Through talking with the project manager, I feel like I know what’s going on in the company and I am confident that I am making the biggest possible contribution to the company’s success.

Technical Debt:

Sometimes, when I’m working on a task, I realize that something related is broken or messy. I may have the opportunity to clean up, refactor, and fix related systems, but this might mean that I will have to work on a task past the estimate. If this is the case, I will communicate the opportunity and consequences to the project manager and she will decide whether or not I should pay some technical debt. If I think I can pay the technical debt within the original estimate for the task, I can make the decision to do so or not, using my best judgement. If for any reason, I cannot fix, clean up, or refactor the problem, I will add a new task with details to the Maintenance Backlog in our chosen task system.

Google Fridays:

Google engineers are allowed to take 20 percent of their time to work on something company related that interests them personally. We all have project ideas that we would like to see happen at the company, which don’t always take priority. I would like to have time to develop and present these to management. A proposal process could determine the most valuable possibilities.

Projects:

The company’s projects follow a predictable and consistent cycle.

Once a project becomes a priority, the project manager works with stakeholders and a primary developer to determine the project requirements. If there is a UI element, a mockup is created. Once the requirements are established, the developer is responsible for writing up the technical specifications in order to meet those requirements, and will assign time or difficulty estimates. The user stories and the technical specifications are broken out and added to the task queue, to be assigned by the project manager to the appropriate team members. The project manager is responsible for maintaining the priority order of the user stories and tasks.

Progress is presented to stakeholders as often as possible (at least once a week) by the project manager and the primary developer. As requirements change during the course of the project, requirements and specifications documents are updated, time or difficulty estimates are revisited, and task queues are modified appropriately. The project manager communicates timelines to stakeholders whenever there is a change.

Maintenance v. Project Development

A dedicated maintenance team is responsible for all incoming bugs, as well as some tasks and features that are not project related. I spend an equal amount of time on the maintenance team as any of my development colleagues in any given year. As a maintenance team member, my queue consists of bugs and tasks initially assigned via support, and tasks in the Maintenance Backlog. If I see opportunities for system improvement, I may be given time to refactor, or I may add tasks to the Maintenance Backlog. The project manager maintains at least one week’s worth of priorities in the Maintenance Backlog. Unless a task is explicitly assigned to me, I take the next item off the Backlog to work on next.