Deserving Each Other

Posted by timgoh
on Monday, August 25

I hate abusing rhetoric, and this is as slippery slope as it gets (with a dash of strawman and a sprinkle of ad hominem), but the quote is so ridiculous that it deserves it.

Sergey Solanik on moving from Google to Microsoft:

I need to know that the code is useful for others, and the only way to measure the usefulness is by the amount of money that the people are willing to part with to have access to my work.

Hmm… by that token prostitutes are more useful than volunteers at nursing homes. Well, with that kind of attitude he sure picked the right place to work.

On Improvement

Posted by timgoh
on Saturday, July 26

Thought of the day: For any significant chunk of code, if you look back at it a month later and can’t think of any way to improve it, your response shouldn’t be “Damn that was good code I wrote”. Instead, it should be “WTF have I been doing for the past month?”

Bit.ly: pissing all over web conventions, and then some

Posted by timgoh
on Friday, July 11

1. No graceful degradation. Par for the course with many web apps these days, but it’s an url-shortener! Two textfields and a submit -button- link require javascript. Welcome to the wonderful world of web 2.0.

2. Speaking of which, the input form is not even that. Come on, it’s not like you can’t make ajax calls with forms.

3. No url validation. Try shortening the url “learn2validate”, and you get a helpful alias to http://learn2validate.

4. Breaks Firefox autocomplete. Because they aren’t using a form and triggering the submit on keycode 13, if you type “ht” in the textfield, scroll down in the history to select your url of choice, and hit enter to choose it, what’s going to happen is that you’ll end up submitting the url “http://ht”.

5. Does not respect cache headers. Jason Levine has a detailed breakdown here

6. Their bookmarklet is not one-click (which disqualifies it as a canonical bookmarklet imo). The bookmarklet simply takes you to the their home page and helpfully fills in the url field. Compare that to TinyUrl’s which creates the url for you with that one click.

I really don’t understand all the hype over Bit.ly. A glowing review from ReadWriteWeb, and people on twitter generally seem to like it. I guess all the shiny stuff distracts from the gaping holes in core functionality. At times like this I really wish uncov was still around to smack them down.

Update

Looking through their page source reveals a ton of WTFs. They have both inline css and a separate stylesheet (I can understand arguments for optimization with one or the other, but both?). The same goes for javascript—directly included in the page as well as in a separate file. Alternating javascript and css inside head. More javascript in body. Unnecessary use of tables (check the source for the footer). It’s embarrassing.

SEO Heresy: Write Good Headlines

Posted by timgoh
on Saturday, June 28

As more and more worshipers gather at the shrine of PageRank (apostle of Google), headlines across the web, be it on news sites or blogs, are declining.

Gone are the days you see quality headlines like ‘Super Caley Go Ballistic Celtic Are Atrocious’ (in reference to underdog Caledonian Thistle beating Celtic in a Scottish Cup match). Or ‘Young Boys Wankdorf Erection Relief’ on the Young Boys football team opening the Stade de Suisse Wankdorf stadium.

Most sites now have boring, generic headlines which attempt to hit the correct keywords, keywords that were painfully assembled by the “SEO analyst” cottage industry and disseminated to everyone who flips them a quarter1.

I remember when Rails 2.0 first came out, and many bloggers jumped through hoops to include the word “restful” in their blog post titles, to the points of absurdity. It wasn’t to the extent of “Restful Deploying with Capistrano” but it ran pretty close.

Why is this short-sighted? Namely because everyone else is going to be competing in the same space with the same keywords. If your SEO tuning is perfect you may end up on the top hits for those terms on Google, but only for a certain time. PageRank has many variables, and you’re only optimizing for one. Newer posts with the same keywords will eventually take over.

Instead, why not craft a memorable headline, one that sticks in a reader’s memory when they want to google for it again? Are you more apt to remember one of the posts titled “Ruby Rake Tasks for Rails” or Rakie Pankie?

The main issue with SEO is that it’s dealing with a semi-black box in a constantly changing environment. And this may be anecdoctal, but I notice that heavily search-optimized sites are generally doing it to make up for their lack of useful content. Sites looking for long-term growth with loyal visitors who help promote their site with word of mouth may want to try a new-fangled, revolutionary method called “content optimization”, or in today’s vernacular, “not sucking balls”.


1 Try googling about SEO sometime. Many of blogs on SEO have repetitive content, practice circle-jerk linking, and generally exude a very foul odor. The majority of SEO blogs are the sewage of the Internet.

RailsConf Recap III: Hosting and the Woes

Posted by timgoh
on Sunday, June 15

This is third in a series of (very late1) RailsConf notes.

Previous recaps:
  1. Custom Nginx modules
  2. Fuzed

Hosting and the Woes

Speakers: Ezra Zygmuntowicz, Jamie van Dyke, Tom Mornini, Taylor Weibley of Engineyard

Primary Materials:
  • Annotated slides (pdf) here
  • Slideshare version here
Additional Resources:
  • eycap gem : $ sudo gem install eycap --source http://gems.engineyard.com
  • Drew Blas’s summary of the same talk

Rating2: A. Pretty much. Yes for B, C, D.

Jamie’s annotated slides pretty much pre-empt any of the notes I took, so that’s what you should be reading for the talk proper. The value-add I have is that of notes for Q&A. I had difficulty noting down the questions verbatim, but I’ve tried to capture as much of their intent as possible.

Q: Memory footprint between ebb/thin/mongrel?

A: Ebb is very fast, but not production ready. Thin, being evented, doesn’t work as well with long actions3. That said, the differences between the 3 servers are trivially insignificant compared to app code: caching, architecture, etc.

“Choice of application server does not determine your scalability”

In the real world, expect around 13% performance increase.

More than 4 cpus/core is wasted, and needing more RAM for mongrels is a common misconception.

“There is no reason to run more than 3 mongrels”

Q: Why no mention of nginx?

A:

“This talk was about woes encountered with hosting. We haven’t really had any problems with nginx.”

“I have seen nginx serve 40mb of static images a second and not show up in top”

(Thanks to Giles Bowkett for refreshing my memory on the second quote—I did not have it verbatim in my notes.)

Q: How best to handle static files

A: EY uses RedHat’s Global File System against SAN-mapped storage. Sharing static files allows cached files and uploads to be available to the entire cluster immediately.

Q: How best to handle asynchronous processing

A: Originally EY used BackrounDrb (natively developed by Ezra). Now they’re using BackgroundJob , or BJ. According to EY,

“BJ is pleasurable”

I don’t think anyone can argue with that!

Q: HTTP1.1 Keep-Alive with Nginx

A: Browsers should make multiple requests, if they do, practically no difference between HTTP 1.0 and HTTP 1.1

My notes for this question and its answer are rather different from Drew Blas’s, and I can’t remember in enough detail to decide between the two. That and my notes for this are very sketchy. Maybe if someone else who attended the talk chimed in?

Q: How is load distributed across servers in server farm?

A: It is basically a mapping of physical load balancing to virtual load balancing. You quickly forget about the virtualization except when you need it in a virtualized environment with very high I/O throughput. One service per host is not ideal application architecture—you should have more than one of everything on each slice (nginx, mongrels, etc)

Q: Does EngineYard have an SLA?

A: Actually instead of the answer I’m going to bait and switch, substituting it with a mini-rant. This is exactly the kind of question you should not ask in a public venue. There are a lot of people who can answer that question besides the panelists from EY. It is an FAQ type question. It is a question that can be answered by anyone at the huge EY booth. So please, if you have a chance to ask questions at conferences, ask yourself: (a) is this useful for anyone else on the floor? (b) is this something I can easily find out from somewhere else?

And that’s it for the Q&A.

There probably isn’t any conflict of interest in this post, but for completeness I should disclose that my company uses EngineYard for various client projects, including 3 of the top 100 Rails sites (traffic-wise). Working with EY has been a great experience—plus there’s lots that can be learned about sysadmin and Ruby-related deployments just by looking at the way they organize things.


1 I’ve had two severe bouts of clientitis in the weeks following RailsConf.

2 See first recap for explanation of ratings

3 Ebb and Thin currently both have ways of dealing with long running requests. See Ezra’s post for details.

RailsConf Recap II: Fuzed

Posted by timgoh
on Sunday, June 08

This is second in a series of RailsConf notes. The first one on custom nginx modules includes background on the raison d’etre for these, and can be found here


Build Your Own Distributed, Self-Configuring Rails Cluster

Speakers: Dave Fayram and Tom Preston-Werner of Powerset

Primary Materials: Additional Resources:

Rating: A: Hell Yes, B: Yes, C: Somewhat, D: Yes (see previous post for what this means)

Dave and Tom started the talk with two choice quotes. One from an Evan Phoenix tweet

“If humans can land robots on Mars, then there is no reason we can’t make a fast Ruby.”

Naturally they pointed out the rather large difference in budgets!

And one of their own:

“No matter how fast Ruby is, we will always need a way to scale it!”

They then launched into a description of traditional scaling.

Simple case: nginx -> proxy-pass to different mongrels

More: nginx -> proxy-pass to mongrels on different boxes

Even more: load balancer -> multiple nginxes on multiple boxen -> multiple mongrels

This was followed by a list of questions which they answered later with regards to Fuzed. I shall practice DRY by not listing the questions here.

Fuzedemo

With that, time for the demonstration to begin. First, on Tom’s laptop:

$ fuzed start -n master volcano.local
$ fuzed frontend -z volcano.local -r test/app/public -s 'kind=rails' -n1@volcano.local -j api

At this point, static assets are up, but dynamic requests can’t be handled yet. Just one more command:

fuzed rails -z volcano.local --rails-root=test/app -n n1@volcano.local -c3

Now we have three Rails workers running on Rack, and dynamic requests can be served.

(More elaboration on these commands can be found on the README at Github )

Then Dave joined in the fun, adding his machine to the mix. The new node was connected to the same cluster, and the master “self-assembled”. They then demonstrated the self-healing ability of Fuzed, taking down a node. The master gave feedback instantly, and the node was replaced.

For the next point, I have an exclamation in my notes: “reports over HTTP!”. Basically, status information can be queried over HTTP. In their example, the root page of localhost:9001 was reporting “There are 1 pool(s) attached to this master with a total of 3 worker(s)”

And this naturally extends to localhost:9001/status/rails/4 reporting “Expected at least 4 worker(s) in the 1 rails pool(s). Found 3.

Now why the exclamation? Because HTTP support provides so much flexibility (Jacob Kaplan Moss’s elaboration of how significant that is for CouchDB is particularly enlightening). Also, the obvious application of this is that the nodes running inside the cluster can be easily be made aware of the bigger picture.

And it was about to get cooler.

But first, the “Fuzedvantages” (their word, not mine!), in the form of answering some de facto scalability questions mentioned earlier:

Fuzedvantages

Q: What happens if a machine fails?

A: It will automatically be taken out of the rotation, and rejoin once back up

Q: What happens if you need to add more hardware fast?

A: No configuration changes necessary. Just add more nodes. They mentioned that PowerSet was running Fuzed on a lot of machines—Erlang can handle it

Q: What happens if you have a mixture of very fast and very slow pages?

A: Fuzed uses “next available resource” queueing. Nodes with long-running requests will not be available so they won’t be overloaded by new ones

Q: What do you do about a staging setup?

A: Run multiple versions of your app in the same cloud!

Q: How do you deal with scaling in a flexible cloud (like EC2)?

A: Puh-leeze. Fuzed was made for a dynamic cloud environment

Q: What happens if you change your hosting environment? (cloud to colo, etc)

A: Change a few hostnames in start-up commands, and you’re done

More advantages given outside of the Q&A format:

  • insanely flexible: multiple dimensions of horizontal scalability
  • front-end and back-end can scale independently * one master node * faceplate (ports connected to the internet): static assets, portal to dynamic assets * worker (rails nodes, other types)

And things that Fuzed does not help you with:

  • scaling your DB (too application specific)
  • raw speed – this is about scaling horizontally, not vertically

FuzedGuts

Basic Fuzed architecture

master node a single Erlang process
faceplate any Erlang process that knows how to translate outside world to Erlang requests
resource_manager monitor over unix pipes talking between masters and workers through ports
  • master creates resource pool, with ‘ports’ that correspond to resource_manager ports
  • faceplate obtains a direct connection to the machine that hosts the resource through the resource manager, which translates the response from the worker from Ruby to erlang

Then a colorful description of a Fuzed Chassis:

Like the River Styx only where Erlang is the Earth and Ruby is Hades.

Chassises (chasses? chassi?) are language agnostic constructs that handle deployment of different platforms (Rails, Merb, Django, etc).

Request is made rack-compliant, sent to Rails rackhandler, which produces a html response. This response is changed to a “yaws-style response” (YAWS is the Erlang server; it expects deeply nested arrays), sent out to a faceplate, and then to the client.

Have a look at how few lines of code the Rails Chassis is.

Code for a simple chassis they used:

require 'chassis'
class AdderNode < Chassis
  kind "calculon" 
  handle(:crash) do |args|
    raise "You asked me to crash, so I did." 
  end
end

Next they had a bonus presentation on a scalable json server, using curl to make a json request and getting json back.

Finally, they elaborated on their to-do list:

  • eliminate master node as single point of failure
  • include additional dispatch details: url paths, http headers, flexible error handling strategies
  • more chassis modules

All in all this was a vastly interesting talk that had the audience oohing and aahing at times. I don’t know if Dave and Tom have presented together before but they handled it with aplomb—both got a good amount of air time and they didn’t step on each other’s toes.

It’s cool that this RailsConf has shown so many new options for scaling that are language agnostic as well (CitrusByte’s own Pool Party which is specialized for AWS is also language agnostic). It’s a strong signal to the rest of the web developer community that the Ruby community is by no means insular. More on this some other time…

RailsConf Recap I: Custom Nginx Modules

Posted by timgoh
on Sunday, June 08

It is rather late for a set of RailsConf recap posts, but I did promise friends that couldn’t make it that I’d take notes and give them what I’ve got. I decided that I might as well post these notes while I’m at it. I realize that in most cases the slides will be available, but I believe there’s enough value added (it’s easier to read prose than slides, some slides are just one phrase that was expanded on in speech, picture slides would be explained, links are clickable etc) to justify my time spent writing it.

I also recognize the code use may be an issue, so:

All code in this post courtesy of Adam Wiggins

Here’s a quick format for how I’ll be rating each talk. I dislike arbitrary X out of Y scores: I’ll be rating each under the following criteria:

  • A. Was it entertaining/interesting?
  • B. Did I learn anything?
  • C. Was I given more resources to follow up?
  • D. Did this help me make a decision?

First three are fairly straightforward. The last means, the talk should help me choose a direction—whether I’m interested in learning more about the subject matter, or if I’m convinced I never want to touch it or hear about it. Either is fine, as long as I left the talk with an opinion.

You’ll notice these are binary yes/no questions, but I’ll be employing fuzzy logic when necessary.

Enough of the preamble, on with the show:

Custom Nginx Modules: Accelerate Rails, HTTP Tricks

Speaker: Adam Wiggins of Heroku

Primary Materials: Additional resources:

Rating: Yes for criteria A, C, D. Emphatic Yes! for B.

Adam first takes us through a brief introduction of Nginx and its place in the future:

Why Nginx? Nginx has replaced Apache for the following reasons: faster, smaller memory footprint, more stable under load, more secure.

More importantly, it is a better fit for Rails. mod_proxy is a bolt on that doesn’t fit well with Apache architecture. Apache is the right tool for mod_php, or owning your own server hardware. But that era is now coming to a close. What’s the new paradigm?

One element of the new paradigm is standalone long running processes. The frontend server just proxies to these processes. Another element is cloud computing, which Adam defines as

“transient and horizontal scalable resources”

A smart proxy can track resources in real-time and route stuff to where it needs to go.

This is where nginx shines. Proxying is nginx’s primary (in fact, only) mechanism for serving dynamic content. It embraces the constraint of keeping application VMs out of the front-end web server. This allows it to be leaner, more focused, faster, and more stable. Adam pulled out the canonical City Slickers quote here: “One thing. Just one thing. You stick to that and the rest don’t mean shit.”

“Wait, there’s something funny going on here”

So, nginx is an intermediary, is it still right to call it a web server? No, because this is a leftover term from a previous era. Adam calls nginx a “HTTP router”.

Here Adam used a Back to the Future metaphor: lightning striking the clock tower just as Doc is connecting the cables. Doc Brown is the http router, and lightning is the http request. The important thing to take away is that your primary goal is just-in-time handling of requests.

Adam then took us through some sample setups1:

Basic nginx conf

upstream myapp_mongrels {
  127.0.0.1:3000;
  127.0.0.1:3001;
}

location / {
  proxy_pass http://myapp_mongrels;
}

With memcached in front

location / {
  set $memcached_key $uri;
  memcached_pass 127.0.0.1:11211;
  error_page 404 502 = @myapp;
}

location @myapp {
  internal;
  proxy_pass http://myapp_mongrels;
}

You’re proxying two completely different services, but from one place. But you don’t want to cache POST requests, so you get:

Memcached in front with method filter

location / {
  if ($request_method = GET) {
    set $memcached_key $uri;
    memcached_pass 127.0.0.1:11211;
    error_page 404 502 = @myapp;
    break;
  }

  proxy_pass http://myapp_mongrels;
}

Next up, Adam tackles filtering, which we’re all familiar with: mod_ssl, mod_rewrite, mod_gzip. He defines filtering as

“reaching in and tinkering with requests and responses”

He then took us to extending the concept to every single portion of requests/responses (headers, bodies, etc). The main philosophy is that the server only needs to worry about serving, and endpoints can be ignorant of what’s going on.

How to use filters for separate concerns:
  • filters in your app for business logic
  • filters in your http router for server infrastructure
  • filters in either for application infrastructure

Adam subsequently “got hardcore”—showing as how an authentication filter (application infrastructure) would be done as a custom nginx module.

The goal is granular user access control. While normally done with a before_filter in Rails, the goal is to have this without any Rails code.

Solution? An input filter module in Nginx, ngx_heroku_gate

Rails version

1. before_filter :authorize
2. 
3. def authorize
4.   @user = User.find(session[:user_id])
5.   @resource = request.env['REQUEST_URI']
6. end
7. 
8. redirect_to '/login' unless @user
9. redirect_to '/access_denied' unless @user.can_access(@resource)

Nginx version

corresponding to line 1
static ngx_int_t ngx_heroku_gate_init(ngt_conf_t *cf)
{
  phase = cmcf->phases[NGX_HTTP_ACCESS_PHASE];
  h = ngx_array_push(&phase.handlers;}
  *h = ngx_heroku_gate_handler;
}
The rest:
static ngx_int_t ngx_heroku_gate_handler(hgx_http_request_t *req) {
  // corresponding to lines 4-5
  user = get_logged_in_user(req->headers_in.cookies);
  app_name = get_app_name(req->headers_in.host->value.data);

  if (!user) // corresponding to line 8
  {
    redirect_to(req, '/login');
    return NGX_HTTP_MOVED_TEMPORARILY; // short circuits everything else
e e}

  if (!user_can_access(user, app)) // corresponding to line 9
  {
    redirect_to(req, '/access_denied');
    return NGX_HTTP_MOVED_TEMPORARILY;
  } 
  else 
  {
    write_heroku_user_header(req, user); // app level code
    return NGX_OK;
  }
}

#define X_HEROKU_USER "X-Heroku-User" 

static void write_heroku_user_header(ngx_http_request_t *r, u_char *user)
{
  h = ngx_list_push(&r->headers_in.headers);
  h->hash = 1;
  h->key.len = sizeof(X_HEROKU_USER);
  h->key.data = (u_char *) X_HEROKU_USER;
  h->value.len = strlen((char *)user);
  h->value.data = user;
}

The helper function code for get_logged_in_user and redirect can be found at Adam’s follow-up blog post

Performance-wise, nginx modules are automatically “insanely faster”. When apps get big, they’re prone to abuse: spam, malicious spiders, etc. With a custom nginx module for authentication, you get to turn away bad requests for very low cost (essentially almost free).

Adam’s closing thoughts:
  • http router is what nginx is evolving into, and can be taken a lot further
  • rack: stacking handlers in a framework independent way
  • merb router is very powerful
  • having inter-process http routing gets you horizontal scaling
  • http is the enabling protocol for the era of cloud computing
  • apps should be changed to take advantage of cloud computing, since web
  • requests are inherently stateless they’re very suited for that

This was exactly the kind of talk I love—no dumbing down, lots of code, has practical applications. Thanks Adam!


1 If I had known these would be available, I wouldn’t have typed like a madman to get all these in. They’re now available on the slides, but I’ll go ahead and copy-paste from my notes anyway to justify my keyboard abuse during the conference!

RailsConf Ho!

Posted by timgoh
on Wednesday, May 28

I’ll arrive in Portland tomorrow night for Twitterpocalypse^W RailsConf 2008. First one for me, should be fun. Targeting mostly the deployment-related talks.

How to find me:

If you’ve wanted to stab me in the face over the Internet for the longest time, or just want to say hi, I’m the asian dude with a ponytail wearing prog-metal t-shirts, and possibly the only one there with no Apple goods anywhere on my person.

Cheers!

TechCrunch on Twitter: Translation

Posted by timgoh
on Friday, May 23

I’m eventually going to write a more formal piece on my company blog, but in the meantime snark will suffice.

TechCrunch has been slamming Twitter and Rails . Let’s have a look at what they’re really saying.

(With apologies to Mark Pilgrim and John Gruber )


[Twitter’s] small team contains a handful of engineers, with only a person or two committed to infrastructure and architecture. He goes on to point out that at Digg the team for network and systems alone is bigger than the total engineering team at Twitter

I have never read the Mythical Man Month. More people are better.

I’ll also ignore the fact that Scribd has more web traffic than Twitter with only 11 total employees, information which I can get from my own affiliate site

The problems at Twitter are often attributed to their use of RubyOnRails, a web development framework.

This sentence gives me an easy way of saying I never blamed RoR for Twitter But of course it’s Rails’ fault, it’s “often attributed”! I will also ignore Evan Williams’s statement ‘Lots of our code is not in RoR, already, though.’

Twitter is almost certainly the largest site running on Rails

There are various ways of interpreting “almost certainly the largest”. One of which is ‘6th largest’.

Utilizing a framework that has never conquered large-scale territory [...]

I don’t consider the 474th or 775th ranked Alexa sites ‘large-scale territory’.

As an out-of-the box framework, Rails certainly doesn’t lend itself to large-scale application development.

I shall now pull terms with no meaning like “out-of-the-box framework” out of my ass. Oh and in case you still haven’t gotten my point, Twitter doesn’t scale because Rails doesn’t scale. Marvel at my skilful use of the non causa pro causa and cum hoc ergo propter hoc logical fallacy combo!

[...] But the old adage of “Good, Fast, Cheap – pick two” certainly applies;

Will trotting out a cliche let me get away with making subjective assertions? Hell yeah!

Rails would do itself no harm by conceding that it isn’t a platform that can compete with Java or C when it comes to intensive tasks

I shall now compare this “out-of-the-box framework” to two languages, without any substantiation. And look at how I wriggled out of that one… I have the “would do itself no harm by conceding” qualifier! I never said it isn’t a competitive platform. And if you read the comments, I’ll show you the intensive tasks I’m talking about that are total CPU-killers, such as waiting on database requests.

What we see at Twitter today is a very useful and popular service, but one with very complex underlying technical challenges to overcome. Twitter will require not only a new architecture approach and a big injection of the best minds they can find [...]

Damn it, I still haven’t hit my required word count. Here, enjoy this poo-poo platter of my best verbiage.

And later in the comments

It wouldn’t surprise me if the DB is falling over on those requests. Also judging by message ID’s and what I have seen so far, their data is in no way segmented – so you have one BFT (big fucking table)

Sorry, did I say their problem was Rails? It’s actually their database architecture! No wait, all of the above! Oh and my superpower is divining a site’s database architecture based the IDs it uses. Why, just the other day I saw an ID on Google Docs and it hit me: “Those guys use BigTable”.

I’ll make random unsubstantiated guesses about their technology instead of investigating with other sites their usage of Twitter’s API and what they’ve found out, or benchmarking Starling .

You want proper investigative journalism or insightful technical analysis? Sorry you’re in the wrong place. This is the “hearsay and hyperbole” section. You’re looking for somewhere else .

History Meme

Posted by timgoh
on Thursday, April 24

Just an “I’m still here, just busy” type post. Originally from Mark Pilgrim

I’ve had this Thinkpad for 3 months, which means I run vim approximately once an hour (this may seem abnormally low, but once I’m inside I use :tabf and :tabe to open more files).


blackwater ~: history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head -n 20
1976 v
1937 cd
1545 ls
1390 svn
883 rake
832 ssi
471 grep
400 sudo
383 cap
349 rm
292 cat
217 ssh
209 ./script/server
209 cp
208 mv
181 riff
179 cdiff
175 scp
168 psql
147 screen

Key

v = gvim -p
ssi = svn stat --ignore-externals
riff = ssh to slice
cdiff = svn diff $* --diff-cmd colordiff

Vim Users, cure your Textmate envy

Posted by timgoh
on Monday, April 07

My exposure to Textmate was all “whoa this looks sweet, but I can’t give up my Vim key bindings and plug-ins”. Fortunately there’s ways to accomplish the look of most Textmate installs and not have to switch away from the best editor out there.

Get Monaco font for Linux

  1. Download the Monaco Linux truetype font Monaco_Linux.ttf
  2. Find out what your font directories are:
    ~: cat /etc/fonts/fonts.conf | grep directory -A5
  3. Create a new directory under one of your font directories and move the Monaco_Linux.ttf into it. For my distro /usr/share/fonts/truetype works:
    # mkdir /usr/share/fonts/truetype/custom
    # mv Monaco_Linux.ttf /usr/share/fonts/truetype/custom/
  4. Refresh your font caches:
    # fc-cache -f -v
  5. If you’re using vanilla Vim, you may have to restart your console application of choice, then change your console font. If you’re using GVim, add the line
    :set guifont=Monaco\ 10
    Replace ‘10’ by whatever font size you would like to use. Do note that there is a space after the backslash (ie the space is escaped).

Get Vibrantink or Vividchalk color scheme

Vibrantink link

Vividchalk link

Jo Vermeulen (contributed vibrantink) has a helpful post with a screenshot comparing the original Textmate theme to Vibrantink and Vividchalk.

Put the .vim file you download in your .vim/colors directory, and you can then add the line

:colorscheme vividchalk
to your .vimrc file.

I personally prefer vividchalk myself.

If everything worked out, you now have the ‘bling’ of Textmate with the functionality of Vim. A winning combination, if you ask me!

Migrating to FeedBurner

Posted by timgoh
on Sunday, April 06

This is long overdue.

Threw up a 301 from the old address at http://www.progprog.com/feeds/atom.xml to http://feeds.feedburner.com/progprog . Please change your addresses to the FeedBurner feed from now on.

Rails won't be mainstream, but that's fine by me

Posted by timgoh
on Friday, March 21

First post!

For the company blog that is.

With my luck, my byline will be truncated in the wrong place by search engines, and searches for my name would turn up “charged multiple times [dot dot dot]” instead of “charged multiple times with method_missing abuse”.

Use plus-addressing with your Gmail address for filtering

Posted by timgoh
on Thursday, March 20

A lot of people know this already, but I’ve seen a few blank faces when I mention it in real life1, so I thought it’s worth a mention.

The gist of it is, joeschmoe@gmail.com, joeschmoe+purchases@gmail.com, joeschmoe+XYZ@gmail.com will all be received by the address joeschmoe@gmail.com, where XYZ is anything alphanumeric. This is very useful because you can filter on the “To” address, which makes it very specific.

So you can use joeschmoe+paypal@gmail.com for your Paypal account, and have a 100% accurate filter for any e-mail from Paypal, no matter what its subject, contents, or From address is. Plus if they ever sell your address to spammers, you would know.

There are lots of possibilities, so try what works out for you. You can have a specific joeschmoe+amazon alias, or register for multiple online stores with a joeschmoe+purchases alias.

If you do this with a brand new e-mail address and never give out the base local-part, you can constantly maintain a zero message inbox, with every incoming mail perfectly filed.

One caveat: not all sites obey RFC2822 to the letter – some of them disallow plus signs in the local-part (I suspect that most times this is not intentional, just incompetence—since it is much easier to copy-paste the canonical e-mail regex than roll your own).

PS. If there really is someone out there using joeschmoe@gmail.com… Mr. Schmoe you have my profound apologies.


1 You know how it is: you’re in a crowded bar, and some beautiful girl comes up to you and goes, “Excuse me, would you happen to know a more efficient way of filtering my e-mail?” while licking her lips slowly.

Career Update

Posted by timgoh
on Thursday, March 20

Well the first two months of 2008 were certainly interesting. Lots of jumping through hoops and paperwork. But the outcome of all that is, I’m now in LA and officially an employee of CitrusByte, a kick-ass web app development firm. My main requirement in looking for jobs is working on fun projects with smart people daily, and CitrusByte certainly scores very high in this regard1.

Being in such an overachieving environment has also made me get off my ass, and I have a bunch of personal projects in the pipeline that I’ll be releasing “any time now”(tm). So do keep an eye out.


1 And no they didn’t pay/force me to write this