Thursday, December 31, 2009

Importance of Haste

Since Hashrocket is one of the top Ruby on Rails shops in the world we want to give back to the community and help as much as possible. Most of the time this is through emails that we get asking us how we do this, how we sketch this, or if what tools we use. That's cool. What's even cooler ... they wrote an email with their questions in it. Do you know how hard that is it to do? It's not easy I can assure you. All kinds of things can race through your head when asking questions via email:
  • How do I address them? (My name is in the "To" address, I know who its to..)
  • Do I make it a formal letter? (hell no)
  • Do I try to be funny first than ask my questions? )You can, just be honest, it's all good :))
  • Do I ask all my questions? (Sure, go for it.)
It doesn't matter how you write the email or what questions you ask. The least I can do is: answer the email quick. And hopefully help.

Next time someone writes you an email asking a question and they're not being a total ass about it, answer it quick. It's the least you can do.



Tuesday, December 29, 2009

GIT: Cause my memory sucks, renaming the author

This work's only if you HAVE NOT pushed to your remote branch yet.


$ git rebase -i HEAD~3


Then *EDIT* all the commits. At first, it will look like the below:


pick 8eefaac Prevent hitting the database twice for same query

pick 636c72g Only check the one column

pick d7a8674 Add followed_on index


You'll need to "edit" all of them so they're popped off the commit stack to be re-commited with a different author. So before you save and quit the file, it should look like this:


edit 8eefaac Prevent hitting the database twice for same query

edit 636c72g Only check the one column

edit d7a8674 Add followed_on index


Now you're at the earliest commit. To change the author all you need to do is:


$git commit --author corey@hashrocket.com --amend


You'll be put into the amend screen for the commit you're doing so now you can save and quit. Your commit should now have the correct author so you can move to the NEXT commit by running the following:


$git rebase --continue


This will bring you to the next commit to change the author on. Just rinse and repeat and you'll be done soon enough. Below are the commandline steps for future reference :)


To start:

$git rebase -i HEAD~3


Repeat the below for each commit:

$git commit --author corey@hashrocket.com --amend

(save and quit here, no further changes are needed for the commit, unless you think there are)

$git rebase --continue


Wednesday, August 5, 2009

Getting Mashed as a start-up


Here at Hashrocket Labs, we follow a philosophy that we think other startups should follow: build something with the bare minimum feature set and release it. Let it grow.

One way to "let it grow" on a budget is to put your application on a host like Slicehost (http://www.slicehost.com). Our slice was the bare minium at $20/month; throughout the course of the day, we repeatedly increased the specs of our slice, but it turns out that wasn't even necessary.

So, what caused our growing pain or "scaling issue"?
ReadWriteWeb had written an introductory article about our new product Tweetblocker that generated some good traffic. What happened after that, was both exciting and stressful.

We got "mashed".

Mashable, a popular online blog, wrote an article about our application that we had no idea about. It was a great thing. We saw enormous amounts of traffic. What came next was what every startup has nightmares about. Our site crashed hard. We did NOT know what was going on.

Was it a Rails scaling issue?
No. The "can rails scale" question has been the most overused question in our community to this day. Yesterday was no exception. The reason our site crashed had nothing to do with Ruby or Rails.

The Problem
One of the views being used was querying the largest table (500,000 records) and was taking around 400 seconds to complete. It was a basic SELECT. The problem code was below:

CREATE VIEW the_view_table AS
SELECT user_id, twitter_id FROM users_friends
UNION
SELECT user_id, twitter_id FROM user_followers

And we were using the following in our code:

has_and_belongs_to_many :our_followers_and_friends,
:join_table => 'the_view_table',
:class_name => 'TwitterUser'

The above union does NOT use the indexes. This wasn't a Rails issue. It was Mysql. Soon as we removed the union and did two separate SELECT's, our queries went from 400 seconds to under 1 second. Our site came back and handle the onslaught of traffic with ease.

The Conclusion
Now we have a web application that is running amazingly fast with the user traffic we're experiencing now. And Hashrocket is fully comfortable with the performance of our application thus far. The code base is clean and has a tiny footprint. The way Rails should be.

Monday, April 13, 2009

REALLYFUCKINGIMPORTANT

Title get you? It got us.  Last week, my pair and I created a file while we were developing that was called "REALLYFUCKINGIMPORTANT".  Inside this file we wrote one line of what we needed to do *this* week.

Usually, you leave yourself a broken test or two to figure out where you left off.  But we didn't do that.  Instead, this morning (Monday), we were wondering what the hell it was that we needed to remember and ran our app in staging and had an epiphany about a feature that we needed to write.  So we had a conversation about what we needed to do and how to go about doing it.

After that we wanted to make sure our local working copy was up-to-date from our git repository.  We checked the current status by running, "git status"...

To our surprise, we had a file named "REALLYFUCKINGIMPORTANT".  After viewing  golden line of wisdom in the file we laughed our asses off. 

Morale of the story: if you must, write to a file with a ridiculous name in your git repository if you don't want to write a broken test first.  Either works well.

Friday, January 30, 2009

Introduce, Speak quickly, to the point, sit down.

I gave my very first Pecha Kucha talk last night.  It was a blast. You get to work with only 20 slides and 20 seconds per slide.  

Why give such a short presentation?
It's 6m 40seconds long.  It won't bore people to death for an hour if it sucks. Yes, your presentation probably bores the shit out of people if it's over 30min. Go fix it!  

Also, it allows for more people to speak in a short amount of time so there's a lot of variety as far as presentation content goes for a group of people to watch instead a long presentation over 1 topic. 

20 slides?
Sounds easy, but it's not.

At first you'll think that it's easy to fill 20 slides.  Then you start to realize 20 slides might be too much when you trim down your content.

20 seconds per slide?
Sounds like a short amount of time, but it's not. It seems long while you practice, but then it's non-existant while you're actually giving the presentation. 

When you do your first run through after you have all your slides, you'll think to yourself that you need more content or words, but I can assure you -- you don't.  If you can picture in your mind that you're having a conversation that flows with the audience, you'll be alright.  Since there's not enough time for people to ask questions until the end, you can flow from slide to slide.

Topic?
You can talk about whatever you want.  To hit a greater crowd talk about something broad. The more specific you get, the less your crowd will understand. You pick. It's your 6min 40seconds of fame.

Video of the Pecha Kucha night will be up as well as the slides from everyone's presentations at: http://www.refreshjacksonville.org/

Wednesday, January 14, 2009

Another contender in the RubyOnRails CMS arena

I was asked to do a quick review of a new CMS called Ansuz. It's available on Github and is being developed currently. A few quick things for those interested in using it:

* It's under development as we speak, so there's a lack of documentation, almost non-existant

* If you're looking for something to get up and running ASAP, you might want to look at RadiantCMS 

How easy is it to install?
Somewhat easy.  It's not as easy as RadiantCMS, but the README on Github did a pretty good job in getting my install up and running in about 5-10min.

Everyone want's their own functionality.. so what about creating my own Plugin for Ansuz?
Luckily, the Ansuz guy's wanted to lower the barrier of entry and used Desert by the Pivotal guys to help with the plugin architecture.  

How hard is it to implement the Plugin that I build?
The act of building a plugin is easier than other CMS's, but implementing it into Ansuz might be another problem.  Since I haven't given quite enough time to actually implementing one, I'll leave this to be discovered, soon.  

Does it have a cool interface like the other CMS packages out there?
No.  Ansuz's admin interface so far is very crude.  You can't knock it just yet, since it's still being developed.  So if you're a designer, help these guys out and jump in there!  The functionality of the admin interface doesn't seem too bad though.  Is it easy to understand? Sorta-kinda. It seems like there might be "too much" going on in the Admin interface, again, this could be dealt with after the majority of the CMS is done.

How's the quality of the code-base if my company were to use it and build on it?
Even though I would love for a company to use my open-sourced code, if it were still under development, I wouldn't feel right suggesting it to be used in production for a critical app just yet.


I'll continue my review and writing some documentation for Ansuz, so if you have any questions leave a comment and I'll see if I can't help you! 

--
update
--
Ansuz uses Engines instead of Desert for their plugins.

Friday, October 24, 2008

FakeWeb; the most awesomest for stubbing HTTP content

On my new open-source project TwitterCompare I wanted to have a better way of receiving JSON data in my tests when using HTTParty.

The following calling is to verify credentials against the Twitter API using HTTparty:

get('/account/verify_credentials.json')


The get() makes a call to Net::HTTP.request. However, I don't want to request data from Twitter in my tests since I'll be running them quite frequently and it's a waste of resources to contact their servers, wait a few seconds, receive some data, and then all my tests finish 5 seconds later as well as data that may change.

The FakeWeb fork by Chris Kampmeier is what I used and it is awesome. It will:
  • Intercept calls to Net::HTTP.request
  • Check to see if the requested URL is one that needs to return test data
  • Returns test data
The interception is automatic once you require the following libraries in your spec_helper.rb:
# spec/spec_helper

require 'fake_web'
require 'open-uri'

To setup which URLs you want to be recognized and stubbed during your tests with FakeWeb do the following in your tests wherever you wish:
FakeWeb.register_uri('http://twitter.com:80/account/verify_credentials.json?', :response => '/testfiles/http_responses/verifiy.response.json.txt')
You can pass :response a string that is a path to a file to return that file or you can have it return a string.

NOTICE: The port specification in the register_uri() call.  You need to include the port for the FakeWeb.registered_uri?(url) to return TRUE on an exact match.

And that's it! 



Thursday, October 9, 2008

Deploying your Webby site

I've been using webby a lot lately.  It's hot for static-like sites.  The site that I've been really digging into Webby with is TheDailyRefactoring.com.

The cool thing about webby is it's capistrano-like deployment.  You can deploy your site after generating it by using the following command:
$ webby deploy
This won't work until after you setup some constants though.  In your "Sitefile" in the root of your webby-application, you need to set the user, host, and directory of where your site is going to be hosted.

# Sitefile
SITE.user = "web"
SITE.host = ""
SITE.remote_dir = "/www/thedailyrefactoring.com"

After that, you can deploy your site immediately! 

Word to the wise, it pays to setup public-key-authentication between your servers to make this process super simple.

Tuesday, September 23, 2008

Blueprint CSS for the Non-designer

I know that I'm not the only developer that sucks at graphic design.  When I'm hacking on a project or attempting to actually finish something useful I always use a CSS website template while doing it from somewhere like Open-Source-Web-Design.org.  I like things to look pretty. Even if it's in development.

That's where Blueprint CSS comes into play.  I've used it on 2 little projects so far and it's marvelous.  It provides a very simple set of rules to follow to lay your site out in a grid-format, much like how a newspaper is laid out (for those of you that actually still read newspapers). 

The downside is, you still have to have a sense of style. 

Some links to help are: 

Photoshop Tutorials: http://psdtuts.com/
Get a feel for what good design is by Allan Branch's Flickr stream of good designs he comes across: http://flickr.com/photos/ispypurdydesigns

Tuesday, August 26, 2008

Damnit, I'm tired of testing!

I lied!  I love it and it's totally helpful in the long-run.

Bryan Liles came up with a cool acronym -- TATFT (test all the fucking time).  As soon as I heard him talk about this at ActsAsConference2008, he instantly made the best possible answer to testing.  It doesn't matter what framework you write your tests in as long as you write tests.

Below are some quick guidelines for your tests to try to make it easier for those that are getting stuck as to "how to test" or "what should my tests contain for this type of test".  By no means are they the answer to all your problems, but somewhere that you can build off of:

Model tests:
  • In rails, I would use rSpec or Test::Unit
  • STRONGLY suggest not to use instance variables
  • If you start to write any code that interacts with an object other than your model, something is wrong with your model, don't try to fix it with shitty tests
Controller tests:
  • In rails, I would use rSpec
  • rSpec Storyrunner is nice, but *I* think it's a completely different realm for those that haven't been used to writing tests for very long
  • Try not to hit the database if you can
  • When dealing with tests that MUST hit the database or SOLR or Sphinx or (OLAP Cubes for those in a Enterprise-y environment) outside of the application code, categorize them somehow to separate them from the faster running tests so you can run them at night or every hour while running your main test suite in seconds
View tests:
  • I hate view tests
  • But I do them with rSpec

Labels:

Tuesday, August 12, 2008

association.is_working_properly?

When working with a team on a project things can get quickly out of sync. However, when working with a geographically seperated team, things can get out of sync before it even happens -- quick. With source control and high level languages of today, being disorganized amongst team members is much better than it was a few years ago, but still still happens just as much.

Things can go wrong while working on a team like this and usually do, quickly like I stated previously. One area they can go wrong is with migrations. This is where an issue can pop up when creating an association between your domain models.

manufacturer = Manufacturer.new(:name => "Chevrolet")
manufacturer.models.build(:name => "Corvette")
manufacturer.models.build(:name => "S10")
manufacturer.save


In Rails, they're supposed to just work and most people can continue building their application without testing to make sure a "model" is associated (added to) a "manufacturer". The issue is if someone on your team blindly creates a migration and checks it in because they think they're a "guru" and don't need to test or run tests before checking-in. This is a major-fail. This problem happened in my current project and stopped development which pissed me off since my pair and I had to go back and fix someone else's mistakes when we should have been able to continue on with the features we needed to implement.

When creating an associated domain model there's usually some sort of change that needs to happen to the database. This interaction or creation of, is created by a human -- you or me.  It's in the form of a migration as well.  The human element introduces a point of failure so it must be tested, even if it's something minor like adding a column that is used by the framework.

The moral of this story is, test everything if a human has changed the state of it.

Labels: ,

Thursday, July 10, 2008

PayPal Sandbox Username/Password error

Developing applications that utilize Paypal can be a bear. I've done it twice so far and for some odd reason Paypal likes to change things up frequently.

After going through the 2,000 steps to signup for a developer



trunk/vendor/plugins/activemerchant-1.3.2/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb


URLS = {
:test => { :certificate => 'https://api.beta-sandbox.paypal.com/2.0/',
:signature => 'https://api-3t.beta-sandbox.paypal.com/2.0/' },
:live => { :certificate => 'https://api-aa.paypal.com/2.0/',
:signature => 'https://api-3t.paypal.com/2.0/' }
}

Wednesday, July 9, 2008

Goals

Goals are a bitch. Over the years of doing research on being more productive or achieving what you really want, I've found goals to be a very powerful force. When a goal is defined in writing, it's tangible. That's why I believe so many people don't achieve what they want these days. Everyone is either too busy to write the goals down or they don't know how. I love examples and they really express what is being taught through application. So to help everyone out, here are some real goals that I made for myself when I first started consulting last year:


* Have 1 customer for atleast 3 months of work
* Atleast 10,000 in the business checking account for 1 quarter
* Not have to bill more than 30 hours a week

That was it, those 3 goals. And 1 of them was severely underestimated while the other two I blew out of the water. You can guess. Had I not written these down, I would have had nothing to shoot for. Lately my life has been filled with other things I really want to do or obtain and those have been turned into goals as well. As of late, the goals that I had last year also included completing a Sprint and Olympic triathlon, which is what I did as well.

The moral of the story is, write it down -- don't open Notepad or Things, use good ole fashioned paper and pencil and write them down on a little notecard and throw it in your sock drawer. I'm not going to tell you to look at it everyday, you'll look at it everyday just because your mind will drive you to look at it since they are things you want.

By doing this, you'll accomplish what you want. You have to want to write them down first though.

Labels:

Wednesday, May 28, 2008

Capistrano full-stack recipes now on GitHub

After bitching and complaining, I've put my almost-complete-capistrano-tasks on GitHub to start maintaining.

I created the tasks to help setup my VPS in as little time possible since I really don't want to be doing sysadmin stuff anymore. Been there, done that a few years ago. I'm done with it. So I created a few capistrano tasks that will take a bare-bones vanilla VPS and set it up to host rail(s) applications.

Originally, I had nginx install and setup as part of it, but ended up deleting it at the last moment before putting it on GitHub. I don't want to deal with Nginx if I don't have to since I really love Apache -- especially with Passenger (mod_rails) now!

So that's the first order of business is to add the http-server setup ASAP! Other than that, just some overall cleaning up will be done and documentation since the tasks were hacked out in as little time as possible to setup my server.

Enjoy and please contribute ;) I'll be making it available as a gem ASAP too since it is usable in its current state, just not pretty -- yet.

http://github.com/cgrusden/capistrano-server-assembly/tree/master

Having an issue pushing to GitHub or other git repos?

After going through all the correct setup steps to put your open-source project on RubyForge or GitHub you try to do a git-push and then receive errors when trying to git-push.

So the question is, did you add your public key (if you created a new one for git'ing) to your authentication agent via ssh-add?

$ ssh-add ~/.ssh/my_public_key


Done.

ssh-add documentation here

Labels:

Tuesday, May 27, 2008

Removing unwanted new files from your SVN working copy

So you have a project in SVN. You create a few new files and decided you just want to delete them via the commandline real quick.

projectroot$ svn st | grep '?' | awk '{print $2}' | xargs rm

Labels:

Wednesday, May 21, 2008

mod_rails : RAILS_ENV fun

When hosting multiple Rails applications using the new mod_rails for Apache, all of the RAILS_ENV variables will default to 'production'.

The way you can change what environment your Rails applications run in is by adding/modifying the following line in your httpd.conf:

RailsEnv staging


This is really the only inconvenience that I've found so far with mod_rails. Surely someone will allow for the RailsEnv variable to be located inside a VirtualHost block.

Apache+mod_rails(passenger)

Wow, this is HOT.

I have been using a shared VPS for hosting my rails/PHP applications and using NGinx to do so. Yesterday I told myself I wanted a better solution if there was one. So on my VPS, I installed Apache and mod_rails (Passenger) in a matter of minutes and had all my sites back up with ease.

I'm glad to be back on Apache, even though most of the configuration and performance tuning I've long become rusty on since alot of new features have come out for Apache.

The fun will continue.

Monday, April 28, 2008

Generating Migrations just got easier for me

I wanted to add a column "content" to the user's table. Most of us run the following to create a migration:

script/generate migration addContentToUsers


That creates a migration with the following:

class AddContentToUsers < ActiveRecord::Migration
def self.up
end

def self.down
end
end



What's generated is pretty green, so we'd have to add some add_column/remove_column statements like so:

class AddContentToUsers < ActiveRecord::Migration
def self.up
add_column :users, :content, :text
end


Lots of not needed work. Why not just enter what we want onto the commandline when we run our migration? Enter the cool generator way of creating a simple migration:

script/generate migration AddContentToUsers content:string


This generates a sweet, simple migration like this:

class AddContentToUsers < ActiveRecord::Migration
def self.up
add_column :users, :content, :string
end

def self.down
remove_column :users, :content
end
end


Hot. Thanks for pointing this out l4rk

Labels:

Monday, April 14, 2008

Gem: eycap

For some odd reason, I had to put double-quotes around the URL for the source in the following for the EngineYard gem that helps with deployment

gem install eycap --source "http://gems.engineyard.com"

Labels:

Plugin: ResourceController

The Mechnical Turk from Argument from design wrote this sweet ass plugin. It cleans up your controllers, removes redundancy -- hot!


http://svn.ardes.com/resources_controller/trunk/resources_controller/

Labels:

Saturday, March 29, 2008

Jamit sucks. Yea, you heard me.

Today I had an epiphany while looking at the codebase of a COTS (commercial off-the-shelf). Don't' get me wrong, I'm all for leveraging someone else's blood, sweat, and tear's for one-low-price. This time was different. It is the shittiest code I've everseen in a product that was purchased.

All over the place you see the following:

Nastiness #1:
//TODO: clean this up

Nastiness #2:
//$siteHeader = mysql_connect()
$siteHeader = get_site_header();

Nastiness #3 through infinity:
Code that is cryptic and forces duplication.

This is from JamitJobBoard.

Jamit, you suck. Plain and simple.

Labels:

Saturday, February 23, 2008

Give your capistrano script some EngineYard config love

I was attempting to deploy the latest changes to the server for the very first time on my machine and got a wonderful little message from capistrano telling me:

`mongrel:restart' is only run for servers matching {:only=>{:mongrel=>true}, :roles=>:app}, but no servers matched

The fix? From what I understand is that you need to tell capistrano that your web and app roles are running mongrel like so:

role :web, '42.69.187.666', :mongrel => true
role :app, '42.69.187.666', :mongrel => true


That should do it for you, should you have this issue.

Thursday, February 14, 2008

RubyJax pairing fun

Tonight's RubyJax meeting rocked out! Getting everyone to pair up and work on something interesting was exciting. I myself was able to work with Russ, really nice guy that wanted to learn more about Rails to kick his ColdFUSION habit!

Also, thanks to the Jacksonville Developer's UserGroup headed up by Jonathan Bates and crew. They sent out a reminder as well as their posting that helped bring in some new faces tonight, thanks guys!

specialized collections using has_many

Here's the following scenario:

You have a ticketing system. You have a User that can create tickets. That same User can be assigned tickets. So how can you specify a has_many for both cases for the User?

Table Schema:

CREATE TABLE User
(
id INT,
title VARCHAR(42),
created_by INT,
assigned_to INT,
)




The answer:

class User
has_many :assigned_tickets, :foreign_key => 'assigned_to', :class => 'Ticket'
has_many :created_tickets, :foreign_key => 'created_by', :class => 'Ticket'
end



In action:
u = User.find(:first)

render :partial => 'tickets/assigned_tickets', :collection => u.assigned_tickets
render :partial => 'tickets/created_tickets', :collection => u.created_tickets

Labels: