bundle, set up a git repo, and then create a new Heroku app
bundle
git init
git commit -a -m "boom"
heroku create
As Heroku is happy running Rack based apps, all we need to do here is include a rackup file named config.ru in the root directory.
config.ru
12345678
#!/usr/bin/env rubyrequire'bundler/setup'require'rack'require'scamp'# respond to somethingrunlambda{|env|[200,{'Content-Type'=>'text/plain'},StringIO.new("It's Alive!\n")]}
This tiny Rack app will just respond to any request with “It’s Alive!” - handy for stopping Heroku apps sleeping on the job. Push it up to Heroku and try it out.
# do the robotscamp=Scamp.new(:api_key=>ENV['CAMPFIRE_KEY'],:subdomain=>ENV['SUBDOMAIN'])# add some rooms, can be ID numbers or room namesrooms=['My awesome room',1234]
Now the basics are in place all that’s left to do is define some simple behaviour and connect to the rooms
Working as part of a large team on a sizeable number of applications, it’s fair to say that I spend quite a lot of time thinking about git. After spotting a recent Railscast on open source contributions, it occurred to me that the process involved in maintaining an open source fork isn’t neccessarily obvious. As a result, I’ve released give, a gem which wraps up some simple git workflow alongside the GitHub API, with the aim of making it just a little bit easier to get started contributing to open source projects.
The setup
gem install give
give only requires that a GitHub user and token are set, you can check this by looking in ~/.gitconfig or from the command line
If either are missing, this GitHub article will walk you throug the process.
With give installed you can now fork a GitHub repository from the command line using the give setup USERNAME REPO command. This example will fork the give project from the user seenmyfate
give setup seenmyfate give
This command uses the GitHub API to fork the project you have specified to your GitHub account, and then clones your fork to your current path. An extra remote ‘upstream’ is also added to the project, pointing back to original project.
Staying current
Once you’re ready to start coding, the give start BRANCH command will create and checkout a new branch to work in
give start feature/my_awesome_feature
To be sure you’re working on the latest code, the give update BRANCH command will rebase your fork’s master branch from the original repository, and then rebase your feature branch.
give update feature/my_awesome_feature
By doing this regularly you can be sure that you are not duplicating work, and also ensure that any code you depend on has not changed since you started work. This should also help your pull request to apply cleanly, allowing the project maintainer to easily pull in your contribution.
Pull
When your contribution is complete, push your changes to GitHub and send a pull request with give finish. Here you must pass in the user and repository to send the pull request, and your local branch.
give finish seenmyfate give feature/my_awesome_feature
You will be prompted to enter a title and body for the pull request.
And that’s it. I hope this gem will encourage more people to make their first open source contribution, and maybe make things a little easier for those who don’t spend all day merging and rebasing with git. I’d love to hear from anyone having success with give, and of course if you have any ideas for improvements, please fork away!
Moving from TextMate to Vim is probably the most significant change I’ve made to my daily development over the last year - and I’m amazed by how much difference it’s made. A few weeks back though this blog post convinced me to go one step further - I took a deep breath and deleted my entire vim install.
Starting over
Following Mislav’s advice, I started out with 13 lines of simple configuration, initially adding only pathogen, the vim-rails plugin and the truly awesome solarized theme. With those staples in place I left my .vimrc file open, made friends with :source $MYVIMRC and resolved to only add a mapping or plugin if my workflow depended on it. Two weeks later I can safely say this is the best thing I’ve done since switching to vim, so here are the highlights from my configuration.
Fuzz Face
Command-T is often suggested as the drop-in vim replacement for TextMate’s popular fuzzy finder functionality, but I heartily recommend the far superior ctrlp. The speed alone is worth the switch, but once you add in regexp mode, the ability to jump directly to a line number, and multiple file opening, Command-T is firmly outclassed.
Force yourself
Between gvim and arrow keys I’ve been cheating for a while, nothing has forced me into dropping some bad habits than locking the arrow keys.
I love split panes, this feature was the main reason I left TextMate in the first place. Opening a split pane and jumping into it is an essential shortcut, quite often followed up with vim-rails’ :A
1
map :vs :vsplit<cr><c-w>l
And some shortcuts to resize the split.
123456
" Resize windows quickly " reset with <c-w>= nmap <c-w>l :verticalres+20<cr> nmap <c-w>h :verticalres-20<cr> nmap <c-w>j :res+20<cr> nmap <c-w>k :res-20<cr>
Whilst I tend not to use tabs as often as I use buffers, I still enjoying being able to flip between tabs quickly when I do.
123
nmap <leader>[ :tabprevious<cr> nmap <leader>] :tabNext<cr> nmap T :tabnew<cr>
Scratch buffer
With the help of the scratch plugin this gives me a quick split for random notes, something I use all the time.
1
nmap <leader>; :Sscratch<cr>
And more
In addition to these mappings I’ve borrowed Gary Bernhardt’s testing functions and really cool shortcuts to scroll the other split window.
Feel free to take my vim for a spin, the vimrc is pretty well documented.
git clone git://github.com/seenmyfate/vim.git ~/.vim
cd ~/.vim && rake
Over the last few months I’ve noticed a growing murmuring from musicians about Spotify and royalty payments, culminating in this Music Week article that inspred this rant.
“Got paid £8 for 90,000 plays. Fuck spotify.”
Fuck Spotify. I mean really? Do you cry when thousands of people downloaded a free track on your website? Are you devastated because your SoundCloud profile has topped 100,000 plays? Are you enraged with the injustice of Radio 1 playing your music to millions of listeners for free and only giving you a measly £60 in return? Such outrage. 90,000 potential new fans? Fuck Spotify.
And it’s not just Mercury Prize nominated artists rushing to alienate their fans, some labels I used to respect are getting in on it as well:
“Spotify will kill smaller bands that are already struggling to make ends meet”
So said Century Media as they pulled their entire catalog.
Well I call bullshit Century Media, even if you filled the late 90’s with glorious metal for me - or at least filled in the gaps between Roadrunner, Peaceville and Earache. This isn’t killing smaller bands - can you honestly stand there and say that a service like Spotify is going to be the final straw for a struggling band? Seriously? It won’t be the unscrupulous promoter that pulls the show when they’ve rented a van and drove 400 miles? It’s not the cost of replacing the gear stolen from an uninsured rehearsal room? It’s not the management paying thousands to move the best support tours out of reach? It’s not the labels unprepared to invest in developing talented bands? There’s an untold number of things that are killing smaller bands and Spotify is way down that list. Surely by the end of 2011 it has to be time record labels grow up and stop blaming the internet for their imminent demise - perhaps they’d be able to capture some higher moral ground when arguing the value of music if they weren’t flooding the market with inane disposable crap.
If you’re a musician, your product is you - it’s your live shows, it’s your publishing, it’s what you can physically sell to real people. You have to treat Spotify exactly as it is, a glorified Myspace player that may (or may not) help you to connect with more fans who - if you’re on top of your game - might just put in the time to care about your music. There’s never been a better time to be an independent musician, so stop being so upset that people are actually listening to your music and be happy that you live in an age where it’s possible to produce a professional sounding album on your goddamn mobile phone.
Update 15/12/11 - for the record, in my last PRS statement Spotify paid me at a rate that would have made 90,000 plays worth £72
This post is based on the talk I presented at the very awesome
Magrails conference in Manchester last week - video is on the way soon. This really was a great event, well organised and well attended. I highly recommend keeping an eye on what the
guys have got planned for next year.
I love testing now, but I wasn’t always this way. Although I could instinctively understand the
benefits of writing tests, I never properly understood the benefits of test driven
development until around 18 months ago when working on my first gem for
OTB. At this point in time, we were suffering under the weight of legacy code. Developing with tests was near impossible. Although we had test suites, they were slow and clunky, spending hours (yes, hours) working through
the code and hammering the database. Sadly for all that effort, they were mostly just testing Rails itself.
Developing this gem I discovered something simple but extremely powerful: tests can be fast as hell. Fast as hell tests can be run evey time I make a change, and their failure can drive my next line of code. It sounds so obvious, but I’d never really experienced speed like this. At the time it was a revelation, and it let me
find a coding rhythm I never knew existed. The general background noise
in my head fell away as I stopped trying to juggle 20 things at once,
I just followed the path I’d laid for myself with my tests and relaxed -
I could code faster, work better and I even had to start using pomodoros to remind
myself to take a break.
Going back to a rails project after this experience was pure pain.
Straight away my
rhythm was shot, and although I tried using workarounds such as
autotest, I found little solace. Frustrated with
waiting for my tests to return with a failure I would forge ahead,
anticipating the failure and writing the code based on my prediction -
when my tests inevitably turned red, I had to backtrack 4 or 5 steps and
try to understand where I had gone wrong. This wasn’t TDD.
Over the last year we’ve made some massive improvements to our test
suites, but we still have a way to go. Even now the application I spend
probably 90% of my day working in at OTB has a test suite that runs in around
10 minutes, and running a single spec will take around 15 seconds. 15 seconds is way too long.
Any creative or cognitive process will suffer dramatically from an interruption. Making these tests run faster is imperitive, to me it’s the same reason I still keep an ancient Fostex 4 Track kicking around ready to record guitar - waiting for my laptop to power up is enough time to completely forget what I was just about to play.
So how can we make this better?
After watching the speed of Gary Bernhardt’s tests on Peepcode, and then later on his Destroy All Software screencasts, I began working some of these ideas into any new code I was writing, and after seeing Corey Haines talk at GoGaRuCo I knew it was time to introduce these ideas to the rest of the team.
So here’s a single spec running in the application I mentioned, which
for the record is a Rails 2.3 application running Rspec 1.3
spec/nowt_spec.rb
12345
require'spec_helper'describe"Nothing"do# nadaend
15.741 seconds total
So what’s taking 15 seconds here? spec_helper - it simply requires our rails environment - the whole thing, no matter which parts of it we actually need.
spec_helper is the best way to write really slow painful specs, because it removes your ability to intelligently choose what you’re loading
So let’s try this running the same test without spec_helper
spec/nowt_spec.rb
123
describe"Nothing"do# nadaend
0.186 seconds total
So by avoiding loading Rails, we get an instant saving of 15 seconds
So here’s the question - for our unit tests, why are we loading the
entire rails environment? In our case, it is because our business logic
is in our Active Record models, and we need Rails to run tests against
classes that inherit from ActiveRecord::Base. But of course by bundling our business logic in with our Active Record models we’re
breaking the Single Responsibility Principle.
Ok so Active Record already breaks this principle, but that’s the Active Record trade off - the trouble with Rails is that it implicitly suggests that we need a 1:1 mapping between our classes and our database tables. This leads to low cohesion, and code that’s difficult to test. When we find ourselves needing to create multiple objects and establish relationships in order to test some business logic in a unit test, it should be raising red flags all over the place - our tests are telling us that the design is wrong, and we need to change it.
A better approach would be to isolate the business rules from the active records and isolate the views from the models. This wouldn’t violate any rails idioms, and would make rails applications a lot more flexible and maintainable.
4 Steps
So with all that in mind, these are the 4 steps we have started to implement:
Extract business logic into modules
Extract domain objects into classes
Mixin and delegate
Test in isolation
The starting point
So here’s a practical example, inspired by Corey Haines’ demo at
GoGaRuCo but also based on real world code from one of our
applications.
Here we’re creating 3 ActiveRecord objects in order to test the
behaviour. By including Rails in our unit tests, we’re subconsciously encouraging ourselves to test Rails.
spec/models/basket_spec.rb
1234567891011121314
require'spec_helper'describeBasketdocontext"total_discount"dolet(:basket){Basket.create!}let(:basket_items){[BasketItem.create!(:discount=>10),BasketItem.create!(:discount=>20)]}it"should return the total discount"dobasket=Basket.create!basket.basket_items=basket_itemsbasket.total_discount.should==30endendend
7.092 seconds to run
And here is the pain - any change to code comes with a penalty of 7
seconds to run the test.
time rspec spec
.
Finished in 0.24435 seconds
1 example, 0 failures
rspec spec 7.092 total
Extract behaviour into modules
The first option here is to extract the behaviour into module. To calculate a
discount we don’t need a Basket object, we can use any object, as
long as it responds to basket_items with an array, and each object in
that array responds to discount with an integer.
The test is becoming simpler. By using a module we can include into any
class, we don’t need to load our Rails environment. To test, we can
create a fake class, mixin the module, and test the behaviour in
isolation using stubs. As
long as the stub responds to basket_items with an array, and each stub in
that array responds to discount with an integer, that’s all we need.
spec/lib/discount_calculator.rb
123456789101112131415161718
require'discount_calculator'classFakeBasketincludeDiscountCalculatorenddescribeDiscountCalculatordocontext"#total_discount"doit"should return the total discount"dobasket=FakeBasket.newbasket_items=[stub(:discount=>10),stub(:discount=>20)]basket.stub(:basket_items){basket_items}basket.total_discount.shouldeq30endendend
0.350 seconds to run
And the benefits are huge, 7 seconds faster.
time rspec spec
.
Finished in 0.00121 seconds
1 example, 0 failures
rspec spec 0.350 total
Extract domain objects into classes
A second option is to delegate, and in this case we can make the code even
more generic. The mixin example above required an object that responded to
basket items, but in this example we can pass in the collection as an
argument.
The test here is even more concise, we only need to create an array of item stubs.
spec/models/discount_calculator.rb
1234567891011
require_relative'../../app/models/discount_calculator'describeDiscountCalculatordocontext"#total_discount"dolet(:items){[stub(:discount=>10),stub(:discount=>20)]}it"should return the total discount"docalculator=DiscountCalculator.newcalculator.total_discount(items).shouldeq30endendend
0.342 seconds to run
And again the test is fast.
time rspec spec
.
Finished in 0.00101 seconds
1 example, 0 failures
rspec spec 0.342 total
The benefits
So to me, the benefits are clear, by taking this approach we can write highly cohesive code,
with lightning fast tests. Once we hit that rhythm of test/code/test/code our tools have moved out of our way, and we can really let our tests guide our code. And that puts me right back in my happy coding place.
The final step
So after a Pomodoro’s worth of red/green/refactor with awesomely fast
tests, there always has to be a final step - run the integration tests.
Isolated unit tests are great, but if anything, they highlight the need
for well written integration tests.
The demo code presented here is available on my
github - please fork away - I’d really
like to see how other people are approaching this. I’ll be
adding additional examples as I come across them, so far these include
testing helpers without spec_helper, and including active_support core extensions
For the last 9 months I’ve been heavily involved in the internationalisation of our main website. Along with making full use of Rails’ excellent i18n API, we’ve also been translating some content on the fly using Google translate. Recently however, Google announced that they would be throttling the number of requests to the Google Translate API v1 service - and would be shutting off the service entirely on December 1st 2011. As Google Translate API v2 has now launched, I looked around for a gem we could quickly plug in and was surprised to find only the google-api-ruby-client - which for our needs seemed to come with a lot of dead weight (buzz? really?).
Given we only require a very limited feature set, I decided to build a tiny gem to meet just that need, and google_fish is the result.
Go fishing
gem install google_fish
In order to test this out, you will need an API key - once you’ve got that sorted, fire up irb
And that’s it, a simple interface to the new Google Translate API v2. Source code as always is up on github - I’d love to hear from you if you’re using this in your projects, and pull requests are welcome.