Posts

Showing posts with the label Code

Iteration Zero

I spent the week doing an iteration zero for new project. The idea behind iteration zero is to get the development environment as automated as possible so developers can spend their time coding when the real development begins. So here's what we did: 1. Set up new git repository We use GitHub so that only took a few minutes. 2. Make new Rails app Again, just a few minutes 3. Set up geminstaller and basic gems (HAML etc.) Geminstaller installs gems needed by the project and makes sure they are there before starting the app. This functionality has been pulled into modern versions of Rails now, but I've found it a little wonky and I'm working with a former Pivotal Labs guy who just loves the Pivotal stuff (don't even get him started on Tracker vs Mingle ). 4. Set up developer tests. We looked into Shoulda , but ultimately went with RSpec (although we may use the Shoulda macros to test ActiveRecord) because most of the criticisms of RSpec are th...

Easy Charging of Credit Cards with Spreedly

When we built SQuiD (easy project management for link building), we had a problem in that the client was on a limited budget and yet the site had to charge people subscriptions for usage. Which, if we wrote that part ourselves, would take all sorts of time to research, implement, and (most importantly) not screw up. When you take people's credit card numbers there is no such thing as a small security breach. Luckily my teammate, Joseph Leddy , remembered hearing about Spreedly -- all they do is "Make Selling Subscriptions Easy." We decided to use Spreedly and it saved us a ton of time (and consequently money). Here's 9 reasons why I loved working with Spreedly: 1. Free to start and test with! Spreedly doesn't charge any money to sign up and run tests against their API. You start paying only as soon as you're ready to start collecting real money. 2. Ridiculously test friendly You can create a pretend (test) area that you can charge accounts to. It looks...

On Going Fast Because You're A Start-up

Today, for some reason, I was thinking about a start-up I worked on few years ago and how we could go really fast because (almost) no one used the darn thing. When you're working on a small budget you need to get that code out into the wild as soon as possible so you can figure out if this idea of yours has any legs. So maybe you test a bit less then you would with a big application and you don't pair program that often and workflow is managed through IM and email and you take shortcuts because if you didn't the code would never see the light of day. That's the way it has to be and everyone accepts that. However, there will come a reckoning -- and it's not fun from the owner's point of view. The site's popular -- it's making some money but your development team is slowing down and asking for expensive things. They've brought on a new guy, but in addition to costing more money the team (which has now ballooned to two people!) is going slower for so...

Different Ways of Installing Metric Fu

Something I didn't mention when I announced the re-launch of metric_fu as a gem is that now, because it's a gem, you have more options when installing it in your project. First option: Vendor Everything . Lots of people are big fans of unpacking gems into the vendor directory of their Rails project (or a similar folder in a non-Rails project) so that everyone who checks out the code gets the right version of the gem. You can then require it in your Rakefile like this: require 'vendor/gems/jscruggs-metric_fu-0.7.6/lib/metric_fu' However... Second option: Conditionally require the gem. When I announced metric_fu back in April, a lot of commentors bemoaned the fact that they would have to install something into their production code that wasn't really necessary for production. I don't really mind doing this as metric_fu does not modify any classes: It's mostly just a bunch of Rake tasks (and some report building code). However, I see their point. So if...

What's a Good Flog Score?

I've been using Flog to measure the complexity of my Ruby code and I was wondering how others interpret Flog numbers. I'll go first with my opinions: Score of Means 0-10 Awesome 11-20 Good enough 21-40 Might need refactoring 41-60 Possible to justify 61-100 Danger 100-200 Whoop, whoop, whoop 200 + Someone please think of the children (note: these are scores for an individual method) The 20 - 60 range is interesting to me. Sometimes the complexity of what you're doing will justify the score and other times the method is in desperate need of refactoring. The highest Flog score I've seen in the wild was in the 300's. What's you're personal high and what do you think of my rankings? In other news, I've redesigned the look of my blog so if you only see my post through a reader you might want to stop on by, take a look, and tell me what you think.

Subversion Password Caching Problem Leads to TextMate svn Integration Problems

I had a problem recently with TextMate's svn integration and finding the solution taught me some interesting things about Subversion and TextMate that I'd thought I'd share: First -- TextMate fails with a non-helpful error message if you don't cache svn passwords. For a long time I didn't even realize that my two problems were related. I had to type in my username and password for svn every-time (even though I wasn't using svn+ssh). And TextMate exploded when I tried to see the svn log of a file. Turns out one causes the other -- obvious in retrospect. Second -- Subversion keeps passwords and configuration files inside a .subversion folder inside the user's home directory. Try looking for a strangely named file inside ~/.subversion/auth/svn.simple for cached passwords. And there's a config file at ~/.subversion/config If you want to stop this caching of passwords you can set: store-passwords = no inside this file. Third -- Subversion will fail to ...

Presenting at Lone Star Ruby Conf

Word on the street is that Lone Star Ruby Conf was one of the best regional conferences last year, so I'm pretty excited to be presenting at the 2008 edition. It's happening Sept 4-6th in Austin, TX and speakers include: Matz, Evan Phoenix, Jim Weirich, The Rails Envy Guys, and too many other luminaries to name. I'll be giving a talk entitled " Using Metrics to Take a Hard Look at Your Code " which is a distilation of my thinking over the past year about how to use numbers not as a hammer with which to beat people, but as a tool to improve your code. Registration just opened up today, but space is limited so go sign up soon.

Disconnecting RSpec from the Database

Recently I spent some time away from RSpec and I did miss it, but one thing especially liked about the testing framework I lived in for 10 months was that it had two ways to test anything you liked: One that hit the database and one that did not. We used UnitRecord to disconnect unit tests from the database (I should mention that we defined unit tests as tests that didn't hit the db and functional tests as those that did). So the vast majority of our tests didn't really need to hit the db and ran very fast. Sometimes we wanted or needed to hit the db and we did (only occasionally in model tests, more often in controller tests, and we kept logic out of the view and only tested views at the Selenium level). It was pretty cool and I'd like to thank the team who set it up before I got there. There's been a lot of talk about whether model, view, or controller tests should hit the db but I've found that there's enough exceptions that it's worth just saying that...

Syntax Highlighting for Ruby Made Very Easy

So I've been making do with lame-o 'pre' tags for my code snippets and my blog looks, well, lame. But the various alternatives for highlighting ruby either didn't work for Blogger or smacked of effort (and you know how I feel about effort). Well, recently I joined Obtiva and I was being all nosy looking at my new co-worker's blogs, when I found Tyler Jennings post about creating Spotlight . Take some ruby code, paste it into the text box, press a button, and you get some html which you copy and past into your blog. You'll have to include the default css in your css file the first time, but that's not too hard. Output looks like this: 1 class Echo < ActionMailer :: Base 2 def copy formatted_message, incident_id 3 users_with_echo_emails = User .find( :all , 4 :conditions => " echo_email is not NULL " ) 5 users_with_echo_emails.reject! {|user| !user.receive_echo?} 6 recipi...

Saving in TextMate

So today, for something like the fifth time, I sat down in front of a TextMate installation that didn't have saving set up the way I like it: Auto save on loss of focus and when running a test (or spec). And, for the fifth time, I had to dig around the internet for the answer. So, as a public service to my future self: Save files when focus is lost: http://macromates.com/textmate/manual/saving_files TextMate --> Preferences --> Advanced --> Saving Save all files when running a test (or spec): http://macromates.com/textmate/manual/commands for specs: Bundles --> Bundle Editor --> Edit Commands --> Rspec --> Run Single Example Bundles --> Bundle Editor --> Edit Commands --> Rspec --> Run Examples for tests: Bundles --> Bundle Editor --> Edit Commands --> Ruby --> Run Bundles --> Bundle Editor --> Edit Commands --> Rspec --> Run Focused Unit Test Change the save drop down to "All Files in Project" Hope this helps, f...

Dead Simple Rails Metrics with metric_fu

Image
Every time I create a new rails project I usually put off writing tasks to analyze the code's quality 'cause it takes time and time is, you know, finite. So I've decided to extract some code into a rails plugin which I call metric_fu. It's a bunch of rake tasks that produce reports on code coverage (using Rcov ), cyclomatic complexity (using Saikuro ), flog scores (using Flog ), and rails stats (using 'rake stats'). It knows if it's being run inside a CruiseControl.rb build and puts the output in the Custom Build Artifacts folder so when you view a build you see this: The coverage report is your standard rcov report: Flog output is thrown into an html file: At the end metric_fu calculates the average flog score per method: You might want to check out my previous posts on what to do with a Flog report: The Method Hit List and When You Should Ignore Metrics Saikuro's output is the same as always: (I changed the warning and error levels for this pic -...

The Bug that Took Down a Release and How I Wrote It

We were disposing of some last minute bugs today and I was reminded of the time, a few projects ago, when I introduced a bug that screwed up a whole release. Let's say that I was writing a pizza ordering web site and, after many successful releases, the Big Wigs at PizzaCo wanted to introduce a new feature that would let customers customize their pizzas even more. In production the user could select style of pizza (thin, pan, stuffed), size, and toppings. There was even some cool logic in place to make sure the toppings were available before being offered. Now, in this brave new world of pizza, the customer would be given the chance to customize each topping. If you chose peppers, you would be given the choice of green, yellow, or red (through the magic of javascript). A choice of onions would prompt the question of red or yellow. Pepperoni? -- regular or spicy? So we wrote the feature, which was difficult, as we had to totally change how we interacted with the Topping Provid...

Ruby Substrings and Testing Legacy Code

Recently Josh Cronemeyer and I were working on writing a game in Ruby. Gosu , a 2D game library for Ruby and C++, and Chipmunk , a 2D Physics engine, do lots of the heavy lifting so we thought it would be a fun Saturday afternoon thing to do. However, the examples had no tests so when we tried to change some stuff, and of course it didn't work, we were all sorts of clueless as to why. Well, wrapping tests around legacy code is not a lot of fun but it is an effective way of debugging. Here's how I like to do it: Step one: Identify potentially troublesome code (As in "What the hell is that doing?"). Step two: Write some tests that verify the functionality of the code. Step three: Pull out the offending code into a method or methods. There's a fair bit of interplay between steps two and three, testing one piece may require extracting it. Step four: Either you've found your problem or you've accomplished four things: 1. You really understand the troublesom...

On Inject, Complexity, and George Carlin

Inject has been stalking me for over 2 years. The year was 2005 and I had decided that I would write a website in this new fangled Rails thing. But while debugging some plugin code I ran into inject. To my java encrusted eyes, it looked like this: weird_thing = dont_know.inject({}) {|m, o| m[o] = some_crazy_method o; m} Holy crap. I had no freakin' clue. I looked up the docs on inject and saw that inject, from what I could understand, was used to add up numbers in an array. Which confused me even more. Of course since then I've come to understand inject, but have remained wary as it can be awful confusing to those new to Ruby. Just recently I wrote about how some teammates and I decided against using it to shorten a method, because the particular use sacrificed readability. Then Brian Dainton wrote about how he loves inject. And finally, my team got in a rather spirited discussion over its use. One side of the argument was that it should be used with care as it...

A Small Rails Site and Why You Should Build One

Image
The other day I was showing Rails off to a friend of mine who wanted to know what all the fuss was about and I realized a shocking thing: I was horrible at starting a Rails site. Why? Because for the last year or so I've been working on large, established Rails codebases. Which is kinda cool as it shows how far Rails has come, but it sucks because one of the very cool things about Rails is how much you can do in a short amount of time. So I resolved to create and deploy a small site as a way to exercise some atrophied muscles and have some good old fun with Ruby and Rails. My father, Leslie Scruggs, is a sculptor and I had written him a pure html site back in 1999. And he maintained it editing the raw html files, creating his own thumbnails, and uploading via ftp. Not the easiest of tasks for a man in his 60's. So I created lesliescruggs.com which has an admin section so he can upload pics and get them resized and thumbnailed with 10% of the effort. Of course I us...

Return to Generating a Unique Number

In a previous post I discussed generating a unique id number for an order in our database. Read the original post for the full story, but to sum up, I decided that playing around with rand(100_000_000) was good enough. Martin Ankerl posted a comment pointing out that I was vulnerable to the Birthday Problem . So after a quick trip to wikipedia, I found out that if you have 23 people in a room you might think you have a 23/365 chance of having 2 people with the same birthdays, but no, your chances are closer to 50%! This is because in a group of 23 people there are 253 pairs each of which have a 1/365ish chance to have the same birthday. The formula to calculate how many are needed to give you a 50% chance of having a birthday collision is: .5 + sqrt(.25 + 2 * 365 * ln(2) ) = 22.9999 Which means the 50% chance of collision mark for 100,000,000 is: .5 + sqrt(.25 + 2 * 100,000,000 * ln(2) ) = 11774.600235771 Holy crap! I'm screwed if I can only have 12,000 orders before I get a...

When You Should Ignore Metrics

Our team has been doing a bang up job of reducing our complexity through our hit list (All of our methods are ranked by Flog score and we spend some part of every iteration picking the worst methods and trying to refactor them.). But sometimes we run into a situation where we prefer a high Flog score to a low one. For instance, this bit 'o code: def is_something?(x, y) x.foo == y.foo && x.bar == y.bar && x.blah == y.blah && # and 10 more lines of the same end which had a Flog score in the 60s. We could have changed it to this: def is_something?(x, y) ["foo", "bar", "blah", # and so on ].inject(true) do | a, b | a && x.send(b) == y.send(b) end end Which gave a us a much lower score. However that first method is crazy simple. Merely glance at it and you know what it's doing. The 'less complex' method? Even an experienced ruby dev would need a moment or two. As for a new dev... I can remem...

Automated Javascript Rails Testing

On my last project we did some javascript unit testing in browser using the unittest.js library from scriptaculous, but because it's kind of a pain to set up and integrate into your build, I didn't get it working on my current job. Which makes me a bad person. However, Dr Nic Williams has made yours and my life easier with his javascript_test plugin for rails. Now I can type: ruby script/generate javascript_test fancy_javascript_file And get a fancy_javascript_file_test.html to test my fancy_javascript_file.js. It's all set up to go right at the javascript file. Just open the html file in a browser and it runs the tests. The sweet doctor explains it all better than me so go check out his site. What I want to talk about is trying to integrate this into your Cruise Control build. The first problem we faced is that the tasks that come with the plugin don't close the tabs created in the browser. So after 10-20 builds, you're going to have way too many tabs an...

Generating a Unique Number

Weird requirement at work today: We needed a number that was alpha-numeric, exactly 11 digits, unique, and non-sequential. At first we thought of using a hash, but MD5 and Sha1 give you way too many digits. We could truncate to 11, but not knowing much about hashing, that made me pretty nervous that we'd have collisions. After a bunch of discussion, we decided on this: MAXIMUM_FOR_10_DIGITS = 0xffffffffff (MAXIMUM_FOR_10_DIGITS + cart_id + Time.now.to_i + rand(100_000_000)).to_s(16) I was thinking about using hex, but I was worried about what would happen if the number got too big and went to 12 digits. So I did this calculation: irb(main):001:0> 0xfffffffffff - 0x10000000000 => 16492674416639 Turns out there's all sorts of room between the lowest and highest 11 digit hex number. Paul and Schubert did some quick calculations assuming lots of carts per day and figured out that we have about 250,000 years before we run out of space. Now since we use a random numb...

The Method Hit List

In a previous post I talked about how my team has a daily metrics build that reports on our code quality. One of the things we measure is the Flog score of our methods (Flog is a ruby program that evaluates the complexity of your methods). We have a standing developer task to look at the top five worst methods in our application and reduce their complexity. Every iteration we try to spend some time looking at a few developer tasks, which are things that don't provide any direct business value but do make our code better, automate some manual process, or fix some technical problem not tied to a bug. Yesterday Chirdeep and I refactored the worst method in our app and while it wasn't easy it produced a number of benefits: First, about halfway though the refactoring we came upon some twisted logic that seemed as if it could never evaluate to false. After pulling in Ali for some consultation, we realized that indeed it would always be true and therefore was a bug. We fixed i...