Here at Killswitch we have a number of fantastic developers from many different backgrounds. Everyone has unique perspectives and experience to bring to the table. Both at Killswitch and in the Rails community as a whole, developers fall into two large categories: developers who started as designers, and developers who started out in computer science.
Superficially, it seems strange that people from two very different fields end up in the same place. Designers often don't want to have anything to do with programming, and many computer science people sneer at 'scripting' languages, viewing them as inferior in performance and functionality to more traditional languages. Upon further examination, though, having developers from both backgrounds makes perfect sense. Many Web designers are interested in the internal back-end workings of their projects and get involved in the programming side of Web development. On the other side, many computer science students are not as enamored with the older, more traditional languages, and want to work with an exciting new language like Ruby.
Ruby and Rails is a large contributing factor to these groups coming together. Rails lowers the barriers of entry to get started building dynamic websites, yet offers a depth of nuance to satisfy even the most diehard of code monkeys. It is a dynamic, living framework, actively being improved daily by thousands of community contributors. Most importantly, though, it makes developing fun for both designer and traditionalist alike.
One Goal, Two Approaches
While we may all use the same language and pursue the same technical goals, differences in backgrounds lead to different approaches to different problems. For example, take looping through a collection in Ruby. Ruby provides two ways to do this: Enumerable#each and for...in. Both do the same job, and both are perfectly valid. However, background loosely dictates the approach used. Those who learned Ruby or Ruby-like languages first tend to use each, while those who learned languages like C first lean toward for...in instead.
In a broader view than idiom choice, differences in background bring different perspectives to development. One developer may work on presentation and visual design first and develop the back-end system to match, where another may start with the framework and work their way to design. Both approaches are valid, but represent a difference in background inherent in Web development. When combined, the end result can amount to more than what any individual approach or component could be alone.
Sum of the Parts
While we each have our own individual tendencies and strengths, the best work comes out of the fusion of both perspectives. We all strive to make ourselves and each other better programmers and better designers, constantly learning both individually and as a whole. In sharing past experiences, current struggles and future plans, we can take the best aspects of our dual-developer citizenship and create something worthy of our combined talent.
Here at The Killswitch Collective, we are frequently building applications that are integrated into the sites we design. Depending on the needs of our clients, these applications can keep track of sales, visitors, registered user activity, you name it. Building these applications is in itself a significant task for our teams of programmers, but for our clients it is only the first step. As we turn over the finished product to our clients, they now have a business decision to make:
Do we simply let our employees using the software figure out how to use it by themselves? Or do we give them formal training in how to use the application?.
This is where research comes in. We strive to program all of our applications as intuitively as possible to keep the learning curve low, but ultimately each business we serve has its own employees with their own unique set of strengths and challenges. Developing training strategies can play a significant role in a company's adoption of new technology with both current and future employees.
Research helps to narrow down what sort of skills your company's personnel should be able to acquire in a training regimen. For simple, straight-forward functions, proficiency may be gleaned from nothing more than help documentation and a little one-on-one time with the software. For more involved applications and workflows, however, it might be necessary for more advanced training. For example, let's say that a site keeps track of sales records, and the easiest way to manipulate this data is to convert it to an Excel format. Excel is a very useful tool for making sense of numbers and drawing correlations between groups of data. Despite its popularity, however, there are still many people in the workforce with little to no experience with the software.
Taking this scenario into account, what would be the best approach to train these people in Excel? A how-to book? An Excel seminar? Hands on training? All of the above? The answer may be different for each organization and ultimately is factored by the overall expense, content expectation and return on investment. To put it most simply:
"What is the most effective way to get my employees to learn _____?"
1. Enroll employees into a training class.
Classes put on by third-parties are usually cost-effective thanks to the group environment. Most instructors have a class size limit (often no more than 30 students) so there is still a degree of one-on-one interaction with the teacher. If there are questions about the subject matter, most instructors are more than willing to help.
Advantages: Affordable (while limited) one-on-one support for students. Reinforceable materials are supplied and resources are developed. Fosters teamwork between cooperating students in the class.
Weaknesses: No oversight on the part of the employer. Classes are often 'one size fits all', so you run the risk of sending students who may find the subject matter to be too basic or too advanced.
2. Send employees to a seminar.
Seminars are by definition large gatherings of people that are there for the same purpose. Most seminars, especially those dealing with technologies, are quickly becoming popular (and crowded) events. Attendance can easily reach from the hundreds into the thousands.
Advantages: Plenty of documentation and information is available. The large numbers can often draw vendors touting the latest technologies and free software samples. Seminars give attendees the chance to network and make contacts with other people in their field.
Weaknesses: The large events can provide distractions from the goal of the seminar: training. One missed keynote lecture or hands-on-event can render a seminar ineffective. Participants have to be active learners to acquire the information they need. One-on-one support can be difficult to find due to the large numbers.
3. Hire a consultant to train employees in-house.
While owning the training facility is obviously a cost-saver, not all offices are adequately equipped or spacious enough to provide an effective training atmosphere.
Advantages: The cost is minimal if the company owns the necessary equipment (computers, white boards, sound equipment, projectors, etc). There are more consultants than seminars and classes available, which gives your company more leverage to broker a cost-effective deal.
Cons: Training either has to occur during the work day (which can impede daily workflow), or on the employees' own time over lunch, before/after work or on weekends (which would require cooperation and compensation). Either way, management should expect push-back and must be convinced of the value of the training.
4. Build your own training regimen.
This can be a daunting task unless you have a good support system, a competent research team and are confident understanding of your employees' skill levels. Many companies have pursued this route and find someone within the company who is an expert in the subject matter. They are asked, "What would you need if you were to learn the subject over? What would need if you wanted to learn the more advanced aspects of this subject?"
Advantages: If the company has subject matter experts who are comfortable with speaking and teaching, this can be extremely cost-effective since they are already on the payroll. It's cheaper to give a nice gift or small pay raise as a thank you than to pay thousands of dollars for any of the other training options. This training can promote teamwork within the company, and it gives employees a comfort level knowing that the expert will still be at the company after training is over.
Cons: Not every workplace has personnel with both the subject matter expertise and the ability to speak with confidence and competence. If an employee is pressured to do so, their training session could be disastrous and leave others questioning management's ability. While peer-to-peer training can have a pleasant familiarity to it, the students may not give the teacher the respect that an outside consultant would receive.
These are certainly not the only options so research, ask around, weigh the evidence and make your choice.
Git is a very powerful source control tool that is quickly gaining traction, especially in the Rails community. Getting started with Git, however, can be quite overwhelming thanks to its 100+ commands. The goal of this article is not to provide a comprehensive guide any means. Instead, this is simply a collection of useful tools and configurations that I have incorporated into my day-to-day workflow, using Git with Rails development using Mac OS X and TextMate.
Installation Essentials
Mac OS X Precompiled git packages: There are easy installers for both Leopard (10.5) and Tiger (10.4), just download, open and install.
Git From Source: If you would rather install Git from source, first download the latest package at git.or.cz. Open the file and cd into its folder, then:
make prefix=/usr/local all sudo make prefix=/usr/local install which git
If the last command returns '/usr/local/bin/git' then you're golden — if not, then you may need to add /usr/local/bin to your path.
Note: When you install from source, you also get the added benefit of being able to use Git to update itself.
TextMate Bundle: Tim Harper, with the help of various other contributors, has been nice enough to publish a very helpful TextMate bundle hosted on gitorious.org. If you feel like contributing (or just looking through the repository) go ahead and snoop around. To install the TextMate bundle:
# may need to create the Bundles directory if it does not exist cd ~/Library/Application\ Support/TextMate/Bundles git clone git://gitorious.org/git-tmbundle/mainline.git Git.tmbundle
In TextMate, go to Preferences > Advanced Tab > Shell Variables and set the TM_GIT variable to point to your installation of Git (ie /usr/local/bin/git). Once installed, this bundle will enable you to do all the common Git tasks such as pull, push, commit, stash, etc. all from within TextMate. It is worth mentioning that it also supports the ability to resolve conflicts with FileMerge, visualize branch history with gitk, and visualize history with gitnub.
Configuration Tips and Tricks
To set up Git's global configuration:
git config --global user.name "Name" git config --global user.email "email" git config --global color.status auto git config --global color.diff auto git config --global color.branch auto git config --global merge.tool opendiff git config --global apply.whitespace nowarn
To alias checkout to co (ie git checkout branch_name becomes git co branch_name):
git config --global alias.co checkout
You can keep all those pesky Mac OS X .DS_Store files from being committed once and for all in a global .gitignore file. The .gitignore file is where you specify all files and patterns you would like Git to ignore.
git config --global core.excludesfile ~/.gitignore echo ".DS_Store" >> ~/.gitignore
At the end of all this, my ~/.gitconfig looks like the following (you could also edit this file directly):
[user] name = user_name email = user_name@example.com [alias] co = checkout [apply] whitespace = nowarn [color] status = auto diff = auto branch = auto [merge] tool = opendiff [core] excludesfile = /Users/anemic/.gitignore
To change fonts in gitk for better readability on Mac OS X, simply edit ~/.gitk and change it to:
set mainfont {Monaco 10}
set textfont {Monaco 10}
set uifont {Monaco 10}
You can set up Git to use TextMate instead of the default editor vim, simply add this to ~/.bash_login or ~/.profile :
export GIT_EDITOR="mate -w"
If you would like to set up some more aliases for less typing on the command line, you can throw these into your ~/.bash_login or ~/.profile as well, for example:
alias gst='git status' alias gl='git pull' alias gp='git push' alias gd='git diff | mate' alias gc='git commit -v' alias gca='git commit -v -a' alias gb='git branch' alias gba='git branch -a'
Initial Repository Setup
Git is a distributed control system, meaning that repositories can exist in many different locations. In the event of a failure of a single repository, other copies exist and can be cloned to minimize data loss. If you are working with a team you may find it useful to use a centralized server as a "main" repository for all users to push to and pull from.
To demonstrate this, I will first set up a standard Rails application:
rails git_test cd git_test
I mentioned .gitignore files earler but only created a global .gitignore. We now can add local .gitignore files to this repository. These can be added to any directory, but I prefer to add one to RAILS_ROOT and another to RAILS_ROOT/log:
mate .gitignore # add in TextMate (will ignore all .DS_STORE file in project) .DS_Store # save and close TextMate mate log/.gitignore # add in TextMate (will ignore all .log files in RAILS_ROOT/log) *.log # save and close TextMate
We already set the global .gitignore to not track .DS_Store files, but these local .gitignore files will be pushed up to the main repository and will be tracked so that every clone will ignore the same files.
We now need to initialize the Git repository, add all tracked files and commit all files to the local repository.
git init git add . git commit -m 'initial import, not tracking any .DS_Store or log/*.log files'
To set up a remote repository, first create a directory on the remote server (ie mkdir preferred_repo_name.git). In this case I will create git_test.git. Copy the .git directory from your local repository to this newly created directory on the remote server:
scp -rp .git user@remoteserver.com:/path/to/repository/git_test.git
Now you need to set up your local repository to track the remote repository so that you are able to pull and push changes:
git remote add origin user@remoteserver.com:/path/to/repository/git_test.git
You are now ready to notify your team members that the repository is set up and ready for them to clone at the specified URL:
git clone user@remoteserver.com:/path/to/repository/git_test.git desired_local_repo_name # desired_local_repo_name is optional and will default to what ever is before .git if not specified hack... hack.. hack... git commit -m "message for change log" git pull git push
Note for Subversion users: clone is like checking out a branch, but instead of just checking out HEAD you get the entire repository history.
Your local repository will pull in any changes from remote that occurred since your last pull, and your local changes are pushed up to the remote server so team members can now pull your changes and push their own.
Merging and Branching
Merging and branching is very easy and inexpensive in Git thanks to how it tracks objects, not files:
git co master git merge [your_branch] git push upstream A-B-C-D-E A-B-C-D-E-F-G \ ----> \ your branch C-D-E G
Now you are ready to go and make changes in your own branch until your next merge into master.
Tagging
One very useful tool in Git is tagging. Tagging allows you to preserve a snapshot of the repository at that time and use it as a reference to easily revert to if necessary.
git tag v1.0.0 -m 'finally a stable release'
To check out or revert to revision v1.0.0 at a later date:
git branch v1.0.0 origin/v1.0.0
This will check out revision v1.0.0 from the remote repository into your local branch v1.0.0. The first advice I would give to a Git beginner is to put a tag on the head revision before making significant changes (just in case).
Troubleshooting and Flexibility
What should you do if you find that you are no longer able to push or pull from the remote repository (ie your local repository has some how gotten corrupted)? First, check to see if you can still run git log. If so, create a patch of all the changes you have made since your last push:
git log git diff [sha1-before-change-from-git-log] [sha1-after-change-from-git-log] > my.patch mv my.patch ~/ cd .. rm -rf git_test git clone user@remoteserver.com:/path/to/repository/git_test.git cd git_test mv ~/my.patch ./ git apply my.patch
This will make a patch of all the changes, create a newly cloned localrepository and then apply the patch. You should now have a fresh copy with your changes and can continue working without any loss. The only drawback is that all the changes made between sha1-before-change and sha1-after-change have now been lumped into one single commit. To combat this, you could make a patch for each commit and then apply each one at a time, committing after each patch.
This is also useful if you are not particularly comfortable with rebase and wanted to take out a prior commit or reorder some commits.
git diff [sha1-before-change] [sha1-after-change] | patch -p1 -R
This way you are able to leave the history intact and remove all changes from sha1-before-change to sha1-after-change.
If you must cause a "rift in the space-time continuum" there is git rebase. This is where the diagram above showing commits and pulls goes right out the window and you are able to order the way Git applies the changes to you local branch.
Warning: git rebase is a bit like juggling knives — if done correctly it can be spectacular but there is an inherent risk of harm if mistakes are made. If you end up losing a finger or an entire limb there is always git gc to resolve this, but that goes beyond the scope of this article.
Another note worth mentioning is that git rebase should never be run on a remote branch or any branch that is being pulled from, as it will cause conflicts for everyone who already has a working copy. It is meant to be run on a local, private branch where you would like to be able to switch up or modify history in a way to make a better, more cohesive patch. If you do find the need to use git rebase, always put a tag (perhaps called BACKUP) on the head of the branch before doing so. That way, no matter what you do, you can easily restore your history by resetting the branch to that tag:
git reset BACKUP
Git's reset command comes to the rescue if you suddenly find your changes FUBARed the code base. If you just want to revert back to HEAD and toss out those changes, you can:
git reset --hard HEAD~3 # will permanently scrap the last three commits and revert your branch git reset --hard HEAD~5 # will permanently scrap the last five commits and revert your branch
When you only want to merge a particular change from a branch (instead of merging the whole branch), Git allows you to just pick one commit from a different branch, apply the changes in revision sha1-rev and commit them to the current branch:
# in the branch you would like to take changes from git log # find the sha1-rev you would like to apply and take note git checkout branch_you_want_changes_applied_to git cherry-pick -x your-sha1-rev
Lets say you are working on a new, not-yet-stable feature. Suddenly you get an urgent request to make a bug fix but you are not ready to commit your other changes. No worries, just stash your local changes away for later reapplication:
# bat phone rings git stash git checkout master # fix bug git commit -a git push # problem solved, back to what you where doing before git checkout [original_branch_you_where_working_on] git stash apply # if you have many stashes you can use 'git stash list' to see all the available stashes to apply

