Have you ever been coloring with your crayons on the back of a Denny’s placemat when your little sister starts putting red where there should have been blue? Now the whole thing’s ruined and you have to start over. If only you had been adhering to proper SCM, or Source Control Management, you could have eliminated the chance of bad coloring tainting your masterpiece while keeping all the things that actually looked kinda cool.
The Safety Net
Every serious software project needs SCM. Building software without it is akin to a tight-rope act without a safety net. SCM will both keep a history of your project back to the beginning and allow a distributed team of developers to work together while maintaining a single consistent view of the code base. With these two things in mind, we’ve woven a net that we think is pretty effective.
Keep Your Wings
In the following example, we’re going to pretend you are trying to add wings functionality to your already existing platformer. Once you know the intended functionality but before programming a single line you need to create a new branch for that feature, or a feature branch. We keep features in their own branches so that it makes identifying the purpose of the new code as easy as possible. Every single commit in that branch, and every line of code in those commits, should be moving the project closer to having functional wings. And if for whatever reason wings no longer become necessary in game, you can easily identify the parts of the project that should be removed.
Each commit in your feature branch should be specific, meaningful, and concise.
Specific - The commit has one small goal within the implementation of the feature. One commit to make the wings show up on your little man, although they might not have flight functionality yet, for example.
Meaningful - It actually accomplishes its intended purpose, a purpose which is a stepping stone to the specific feature’s completion.
Concise - The problem is solved with as little code as is needed. If you follow the above three guidelines for your commits, they come with the bonus of being atomic. What this means is that you get a tightly woven and highly readable series of commits which stay small and focused, and allow easy debugging and promote easy peer review.
So you’ve finished your feature and that character can fly like a badass. Even better, you managed not to break everything. The next step is to share the gift of flight with the rest of the project. But before that happens you need another pair of eyes on your code to make sure you didn’t make any unnoticed mistakes. At the surface, that person is just making sure your code is readable and doesn’t contain typos. But a true code review should go deeper, delving into the big picture which includes looking out for some of the big bad issues like dependency injection and coupling / cohesion.
Possibly most importantly, having at least two sets of eyes on every piece of code decreases the chance of siloing. Siloing occurs when one person owns a piece of code and they are the only developer that knows how it works. If it breaks or needs debugging, then the project has to wait for a single person to fix it. Even worse, if they leave the project than 0 people know how it works. Having an extra team member who understands the code and can explain it to others completely removes the dependency on a single person. If Jurassic Park had used peer review, we would all be riding triceratops right now.
We use GitHub’s pull request feature for both code review and merging. Their interface allows for collaborators to view diffs, commits and even comment on specific lines of code. When you open a pull request, you’re offering your code to the game and its worth must be proven before it is allowed to mingle. If it passes the peer review and is merged, then finally your men are given the gift of flight.
What are these releases, and how do they work? A release branch is a branch with no incompletes. Every feature in master works and is relatively bug free. Every single release branch commit should be a completely playable game. That game might not have all the important bits yet, but what is there works. At the end of each workflow iteration, which for us is a single week since we’re all working remotely, we double check that all of the merged features work together and then merge the release candidate branch into master. We then increment the game’s version and begin a new release branch. Thereby you continually are adding features to your master while ensuring it’s never broken as there is a double redundancy in place, both the pull requests review and the release branch playthrough.
Here you can clearly see where everything branches off near the beginning of the sprint and merges back down near the end
Breaking master is a big deal and fixing it tends to be a pain. But luckily Git has some built in insurance. Merge commits (which are made when a pull request is merged into release or release is merged into master) contain all commits from one branch when it was merged into another. This means that if a feature is actually broken, despite having made it through testing and review, you have a way to quickly reference every commit related to the problem in order to hunt it down.
By utilizing master branches, release branches, feature branches, and atomic commits; your changes are structured in a way that contributes to ease of removal and/or editing if things go wrong. This tiered structure compartmentalizes changes and segments them into the most granular structure possible so than any change can be isolated and any bug quickly squashed or removed. You are the steward of your game, care for it, protect it, and help it grow in a healthy manner.