Friday, January 30, 2009

nice module pattern

This is a really nice pattern for mixins. It allows for clear separation of instance and class methods and allows you to cleanly specify constants and call any class methods you need.

module VarkLogging
# any constants you want to define
VARK_LOG_MESSAGE = "vark log!"

def self.included(base)
base.send(:include, InstanceMethods)
base.send(:extend, ClassMethods)
base.class_eval do
# any class methods we need to call
alias_method_chain :add, :vark_logging
end
end

module InstanceMethods
def add_with_vark_logging(*args)
puts VARK_LOG_MESSAGE
add_without_vark_logging(*args)
end
end

module ClassMethods
def vark?
true
end
end
end

# and if you want to include it without altering the original class definition:
Logger.send(:include, VarkLogging)

Mounting extra disks on ec2 instances

First, compare available partitions with
 ~>  cat /proc/partitions
major minor #blocks name
8 16 440366080 sdb
8 32 440366080 sdc
8 48 440366080 sdd
8 64 440366080 sde
8 1 10485760 sda1
~> df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 9.9G 1.6G 7.9G 17% /
/dev/sdb 414G 199M 393G 1% /mnt
none 3.6G 0 3.6G 0% /dev/shm
Here we note that /dev/sda1 and /dev/sdb are in use, while /dev/sdc /dev/sdd and /dev/sde are not yet in use

We want to check the fstab to see what the disktypes are. Also edit this file if you want your mounted disk to come back up on a reboot! (In Ec2-land all of these filesystems are non-persistent, so if your machine more than reboots, you'll lose the data entirely.
 ~>  more /etc/fstab
/dev/sda1 / ext3 defaults 1 1
/dev/sdb /mnt ext3 defaults 0 0
none /dev/pts devpts gid=5,mode=620 0 0
none /dev/shm tmpfs defaults 0 0
none /proc proc defaults 0 0
none /sys sysfs defaults 0 0
Create your mount point:
 ~>  mkdir /mnt2
Mount the disk:
 ~>  mount -t ext3 /dev/sdc /mnt2
And check its availability:
 ~>  df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 9.9G 1.6G 7.9G 17% /
/dev/sdb 414G 199M 393G 1% /mnt
none 3.6G 0 3.6G 0% /dev/shm
/dev/sdc 414G 199M 393G 1% /mnt2

Dealing with Capistrano's cached-copy when switching the branch you're releasing from

Capistrano's default setup tries to deploy from a repository location you specify, and does so by updating a cached-copy on the remote servers using "svn up", and then recursively copying the updated cached checkout to a date-tagged copy under the releases directory.
e.g., when capistrano executes
~> cap deploy:update
it runs something like the following:
executing “if [ -d /deploy/myproject/shared/cached-copy ]; then svn update -q -r3131 /deploy/myproject/shared/cached-copy; else svn checkout -q -r3131 https://svn.example.com/svn/myreponame/tags/release-1.2.1/myproject /deploy/myproject/shared/cached-copy; fi”
This can cause some problems when you try to switch the repository branch you're deploying from, say, to roll back to a tag, or deploy from a radically different stable branch where svn up won't run properly because of deleted directories etc.

So, before you release from a tag, you have to remember to delete the cached copy checked out on the servers. Capistrano's invoke comes in handy for these situations:
~> cap invoke COMMAND="rm -rf /deploy/myproject/shared/cached-copy"
You might want to also remember to delete the cached-copy *after* you deploy too, in case the next person who comes along doesn't realize that you deployed from a strange location.

i can't believe it's this hard to set default values at the AR object level (not the db level)

This is what I had to do:
  
before_save :maybe_set_source

def maybe_set_source
self[:source] = source_name if !self[:source]
end

def source
self[:source] || source_name
end

# The default value I want to set
def source_name
File.basename(RAILS_ROOT)
end

Really?

interesting short article about the spyware arms race

http://www.schneier.com/blog/archives/2009/01/interview_with_10.html

--
Love,
Fritz

Thursday, January 29, 2009

assert_yields

I got sick of writing longhand assertions around yields so I whipped up this little function:

  
def assert_yields(something_callable, arg)
yielded = false
something_callable.call(arg) do
yielded = true
end
assert yielded
end

# Called like:
assert_yields(some_obj.method(:do_something), my_arg)


One could easily make it handle a variable number of arguments.

Object is not missing constant Question!

when Rails says, "Object is not missing constant Question!" -- here's what happened:

You referenced a class that wasn't defined, so ActiveSupport's dependency resolver kicked in.

It loaded the appropriate file (in this case question.rb), but during the load an Exception was raised. The error was not, however, in your class definition, so the missing constant (Question) was successfully defined.

The resolver then catches that exception, expects that your class will not be defined but finds that it is, and decides to throw an "Object is not missing constant Question!" because it's confused.

and from the if-only-they-knew department...

http://www.youtube.com/watch?v=5WCTn4FljUQ

--
Love,
Fritz

tell it, joel

On how not to write a resume for a startup engineering leadership
position (and, by implication, what to look for):

http://www.joelonsoftware.com/items/2009/01/02b.html

--
Love,
Fritz

Wednesday, January 28, 2009

overriding string comparisons

Monkeypatching = Bad. Aliasing = Not Bad. See r7311. It blew up
because Question was also overriding String#==.

--
Love,
Fritz

this should come as no surprise

but don't override AR initialize():

http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html

In fact, don't override anything in AR :)

--
Love,
Fritz

Friday, January 23, 2009

chill that Dock out!

How to keep icons in your mac os dock from performing their g-darned,
vatter-effing bouncing when they want your attention:

http://www.macworld.com/article/138403/2009/01/dockbounce.html?lsrc=rss_weblogs_macosxhints

--
Love,
Fritz

Thursday, January 22, 2009

great splunk howtos

using a simple tcp logger implementation:
http://www.igvita.com/2008/06/19/splunk-your-distributed-logs-in-ec2/

using syslog-ng:
http://www.igvita.com/2008/10/22/distributed-logging-syslog-ng-splunk/

github plugin architecture

http://github.com/pjhyett/github-services/tree/master

AR constructs chained named scope queries in the order opposite what you'd expect

Here's a good one. Consider this chain of named scopes:

Conversation.in_the_last(1.day).
with_question.
not_error.
not_canceled.
not_flagged.
not_answered.
not_involving(user)


You'd expect the created_at restriction to come first in the resulting SELECT, wouldn't you? Nope:

SELECT * FROM `conversations` WHERE (((((((NOT EXISTS (SELECT chs3.id FROM channels chs3 WHERE conversations.id = chs3.conversation_id AND chs3.user_id = 176)) AND (NOT EXISTS (SELECT chs2.id FROM channels chs2 WHERE conversations.id = chs2.conversation_id AND chs2.answer_request_response = 'answer'))) AND (NOT EXISTS (SELECT chs1.id FROM channels chs1 WHERE conversations.id = chs1.conversation_id AND chs1.flagged = 1))) AND (`conversations`.`canceled` = 0 )) AND (`conversations`.`error` = 0 )) AND (EXISTS (SELECT chs4.id FROM channels chs4 WHERE conversations.id = chs4.conversation_id AND chs4.asker = 1 AND chs4.has_question = 1))) AND (created_at > '2009-01-21 16:38:23'));

AR sticks it at the end of the query and as a result it runs in 6-10 seconds on acceptance (w/no query cache). Applying the created_at restriction at the end of the chain constructs a query with it at the beginning:

Conversation.with_question.
not_error.
not_canceled.
not_flagged.
not_answered.
not_involving(user).
in_the_last(1.day)


SELECT * FROM `conversations` WHERE (((((((created_at > '2009-01-21 18:07:29') AND (NOT EXISTS (SELECT chs3.id FROM channels chs3 WHERE conversations.id = chs3.conversation_id AND chs3.user_id = 176))) AND (NOT EXISTS (SELECT chs2.id FROM channels chs2 WHERE conversations.id = chs2.conversation_id AND chs2.answer_request_response = 'answer'))) AND (NOT EXISTS (SELECT chs1.id FROM channels chs1 WHERE conversations.id = chs1.conversation_id AND chs1.flagged = 1))) AND (`conversations`.`canceled` = 0 )) AND (`conversations`.`error` = 0 )) AND (EXISTS (SELECT chs4.id FROM channels chs4 WHERE conversations.id = chs4.conversation_id AND chs4.asker = 1 AND chs4.has_question = 1)))

Apparently it can now use the created_at to eliminate rows in the scan. The resulting query time is about 300ms on acceptance (again, w/no query cache).

Tuesday, January 20, 2009

2 gems from SmugMug

I think smugmug is an organization worth emulating. They do what they do with 40 employees, and were far smaller for most of their existence. If you haven't yet, read about their deployment on ec2: simple, well-designed, and nearly fully-automated:
http://blogs.smugmug.com/don/2008/06/03/skynet-lives-aka-ec2-smugmug/

Also here are some pointers from them on mysql; the recommendation on Percona is something we should keep in mind should we need to call in some db expertise.

http://blogs.smugmug.com/don/2008/12/23/great-things-afoot-in-the-mysql-community/

--
Love,
Fritz

Monday, January 19, 2009

Anti-RDBMS: A list of distributed key-value stores

Richard Jones of Last.fm talks about his research and notes on distributed key-value stores.

Anti-RDBMS: A list of distributed key-value stores

Friday, January 16, 2009

Craigslist uses Sphinx

Well, I guess the cat's out of the bag! My first project at Craigslist was replacing MySQL FULLTEXT indexing with Sphinx. It wasn't the easiest road in the world, for a variety of reasons, but we got it all working and it's been humming along very well ever since.
I'm not going to go into a lot of details on the implementation here, other than to say Sphinx is faster and far more resource efficient than MySQL was for this task.

http://tinyurl.com/7gkwbz

edge rails just got nested transactions

http://rails.lighthouseapp.com/projects/8994/tickets/383

--
Love,
Fritz

Thursday, January 15, 2009

new in rails 2.2

http://guides.rubyonrails.org/2_2_release_notes.html

I definitely don't understand all the implications of threading or
connection pools. The automatic memoization is cool though.

--
Love,
Fritz

Building products users love by giving them control

A fun product design article from pcworld focused on consumer product designers and where they've gone right and wrong, emphasizing a theme of control that is somewhat relevant in our case.

http://www.pcworld.com/businesscenter/article/156305/memo_to_vendors_heres_how_to_build_a_winner.html

Finding unused indexes in mysql

Looks pretty easy to use:

http://hackmysql.com/mysqlidxchk

--
Love,
Fritz

Test

This is a test of post-by-email.

--
Love,
Fritz