Living with Sublime Text 2 for a week

I’ve been looking for a text editor that has been as good as TextMate (v1). I finally jumped in to try Sublime Text 2 about a week ago. Here’s a quick review:

Pros

  • Very fast.
  • Better grasp of syntax highlighting in complex situations.
  • The Goto Anything/search-all (Cmd+P) command is very quick and really nice.
  • Project remember their last state of opened files.
  • The Minimap turns out to be really useful as an oversized scrollbar handle.
  • Global + user overrides for almost all settings. Immediate effect of settings.
  • Package Control.
  • Bookmarks—but they’re not persistent.
  • Split screen.

Cons

  • Customizing themes requires scripting. Almost everything requires some configuration.
  • No interactive theme customization.
  • Almost everything powerful is a plugin. Thank goodness for Package Control.
  • To filter dotfiles and other directories that ought to be hidden is a project-level setting EDIT: can be set globally if you read the unofficial documentation.
  • Doesn’t have a good reveal-file-in-project-hierarchy command. There is a way to reveal a file, but if the containing folder is already open nothing appears to happen.
  • Documentation isn’t super tight—Google is the best way to get help.

What makes easy things … easy?

I had a thought this morning: “easy” things are easy because they’re familiar.

Do you remember the first time you tried to drive a car? It was a nightmare! The coordination between your hands and feet, reading traffic, getting used to looking in the mirrors. And now you do it effortlessly: you jump in, tune the radio, adjust the climate controls … all while being distracted by talking on your cell phone! The task of driving from home to work involves hundreds of individual steps and requires constant vigilance, but I can’t think of anyone I know that says “driving to work is too hard, so I’m not going in today.”

I went on the Net this morning to look around for an article to quote:

On the surface, easy is what we already know how to do or that which takes little mental or physical effort.

The Difference Between Easy And Difficult, Alex Licherman, M.D.

I’ve been building a new piece of software which is aimed at making a very complex task really easy: building a website. I did a Google search for “website builder easy” and got back 4.1 million hits. You would think if websites were so easy to build that one of these millions of links would actually do the trick. But I don’t think any have hit the mark quite yet.

What makes building a website “easy”?

I’ve been keeping a running list of hosted services and what easy really seems to have boiled down to is one trick: what you see is what you get. Sorry, WYSIWYG isn’t anything new. Yes, you can “drag and drop” all of these “modules” or “widgets” onto your site, but does that really make it “easy”? I argue it does not. What it does is leverage your innate ability to grab a colorful block and position it on the floor in front of you. Even after you put this module/widget on your site canvas you still have to decide how to style it, what to write in it, and how to arrange it so it complements the other modules/widgets on the page. Next you need to repeat this process for the umpteen pages on your site. Sure, templates bootstrap you by giving you graphics and layouts, but you still need to customize them all to your liking. Oh, and let’s not forget what I consider to be the real evil of having a website: maintenance.

That’s right. You spend days/weeks tweaking your website so that it’s beautiful, shiny, modern, flashy, ________ (insert other cool adjective) and then you release it to the world. … time passes … Then something needs to be updated. Then all those glassy reflections on your images start to look dated so you want to go with the new design style hotness but there’s oh-so-many pages and icons and Adobe Flash files you need to update… The cost of owning and maintaining your site just went from trivial to white-hot painful. So “easy” really wasn’t, eh?

I think the easiest hosted website to maintain in my opinion isn’t even really a web site: it’s your Twitter account. You pick some colors, you change your background image, and that’s it. This means you focus on your content. And you change your mind about the style later then it’s so simple. Plus, since you have that muscle memory of having gone to the Settings page -> Design tab, it’s easy for you!

What I’m building is something along these lines. For site owners it will make choosing your style so trivial that changing your mind about something will be effortless. The site editor will require you to learn only a couple of interface navigation concepts and only a handful of terms. Instead of giving you free reign over any number of layouts and templates, there is only really one. Instead of creating deeply-nested site hierarchies, it’s completely shallow. Instead of allowing you to do everything you could ever want to do (which in turn necessitates a complex editor), you get to only do a few things but you’ll do them so well.

More importantly, let’s consider the end-user experience: what will your customers see?

Good user interfaces on the web (or any device) have consistent, predictable interfaces. (I’m not the only one with this view.) Users will only need to get used to one visual layout, which means the organization of the rest of your site is also predictable. This in no way means that your site will be boring! It simply means that your design will have a higher degree of synergy. And synergy leads to familiarity. And familiarity leads right back to Easy St.

You win. Your viewers win. Even your graphic designer that helps you with your site wins.

This is my hope. Let’s see if my bet is right?

Devise for authentication … niiiiiice …

In the spirit of retraining myself this summer I was skimming Ryan Bates’ RailsCasts site and I saw an authentication solution, Devise. This is perfect because right now I’ve been trying to figure out what to do about logging users in. I’ve been using home-grown solutions for a while and I’ve seen good things about Authlogic. But Devise, wow. Talk about awesome.

One of the things I’m really liking about it is its modular configuration. Want the user to confirm their new account? No prob, just enable the :confirmable module in your user model. Want Devise to generate the basic views for you? Sure, just run the generator: rails generate devise:views. (You might have to use script/generate devise_views for Rails 2.3.) It’s seriously awesome.

See the RailsCast that talks about it http://railscasts.com/episodes/209-introducing-devise or the GitHub for the project: http://github.com/plataformatec/devise.

Deploying Rails with Github, SSH keys, Capistrano, Apache, Passenger

This is why I am not a sysadmin. I just spent the better part of this evening figuring out just how to get my latest app deployed to my production environment with Capistrano. Sure it is in fact easyish deployment, but you have to know the dance of how it all comes together. And there’s a lot of steps. I wrote this post to hopefully pull together a whole bunch of different information rather than have you read many separate links.

So first off, here’s my setup:

The Setup

Local Development

  • A Mac laptop w/ Snow Leopard (10.6.4)
  • Rails 2.3.8
  • Capistrano 2.5.19
  • Passenger 2.2.8

Source Repository

Production Server

  • Red Hat Enterprise Linux on a virtual server
  • Passenger 2.2.15
  • Apache
  • MySQL

The Plan

  • Add Capistrano to the app
  • Create a private Github repo for the app
  • Create release branch
  • Create an app-specific user
  • Publish to the production server

Add Capistrano to the App

This first part is fairly easy thanks to:

capify .

If you end up creating the Capfile yourself you should be aware that capify does add a few extra goodies to the file:

# Capfile

load 'deploy' if respond_to?(:namespace) # cap2 differentiator
Dir['vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }

load 'config/deploy' # remove this line to skip loading any of the default tasks

There wasn’t much I needed to do to the Capfile itself since I don’t have any custom tasks. But there was a bit of setup that needed to happen in the deploy.rb file. One thing to note is that I ended up switching my SSH port to a different one when I set up my server, so that explains the port on the roles:

# deploy.rb
set :application, "coolapp"
set :repository, "git@github.com:MYUSER/MYREPO.git"
set :deploy_to, "/var/www/APPNAME"
set :user, "app_deployer"
set :branch, "release"
set :git_enable_submodules, 1
set :use_sudo, false

set :scm, :git

role :web, "www.coolapp.com:12345"
role :app, "www.coolapp.com:12345"
role :db, "www.coolapp.com:12345", :primary => true

# Passenger stuff
namespace :deploy do
 task :start do ; end
 task :stop do ; end
 task :restart, :roles => :app, :except => { :no_release => true } do
 run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
 end
end

The :repository is my private Github repo. The :deploy_to points to the directory that will hold this Capistrano-based deployment—there is a trick I had to do on /var/www. I created a new Unix user app_deployer. I also have a release branch that is only used for Production pushes. I have submodules, so :git_enable_submodules is set. Since this is a non-privileged user we can’t use sudo. And finally, on the roles you’ll see that I’m SSHing to the production server www.coolapp.com at port 12345.

Rather than deploy straight from the master branch (which I think is just a horrible idea), I created a branch called release. To sync master to release I wrote a quick script:

#!/bin/bash
#
# script/sync_master_to_release.sh
git checkout release
git merge master
git checkout master

Github

I’ve started using Github a lot more. While I’m a big fan of having an in-house server to hold my oh-so-precious source code, I just can’t be bothered to admin it or set one up. Plus I want to be able to connect with other collaborators. So Github seems to be the best way right now to do so.

I set up a paid account so I could get some private repositories. Just a couple clicks of the mouse later and I had a repo set up for this project. The setup instructions are really clear. Since I had a local Git repo for this project on my laptop, all I had to do was add Github as a remote:

git remote add origin git@github.com:MYUSER/MYREPO.git

(I did in fact have an origin already set up, but I just had to remove the config info in .git/config before running the above line.)

Doing a git push origin master loaded up the Github repo in a flash. And to get the release branch up there it’s just a case of doing a git push origin release to make it aware there’s another branch. Subsequent git push-es pushed up all the objects for both branches.

At this point what I had was an app that was ready to be released to the world and I needed Capistrano to do its deployment magic. But I didn’t just want to grant full access to the deploy script. I don’t want the chance that someone could add tasks that could walk all around the filesystem if they got a hold of the SSH keys…

A User for Deployment

The great thing about Unix/Linux is you have all these permissions so you can lock down directories. The annoying thing about Unix/Linux is that you have to configure all of these permissions. :(

I SSHed into my production environment as my root user via a plain ol’ terminal and created a new user in a new group:

sudo /usr/sbin/useradd app_deployer
sudo /usr/bin/groupadd deployments

(There was also a step to update the password for app_deployer.)

Then I had to associate the new user and the web server user with the newly-created group in the /etc/group file:

deployments:550:app_deployer,apache

I’m deploying to

/var/www/APPNAME

but when you run Capistrano for the first time it wants to create certain directories. Just for a few minutes I changed the main web directory to world-write permissions:

sudo chmod 777 /var/www

Finally, I could then run Capistrano for the first time:

cap deploy:setup

(Note: Remember that even though I SSHed in via a terminal as a root user, Capistrano’s config file has been set to log in via the “app_deployer” user.)

Once the directories were set up I could twiddle the permissions back to normal locked-down mode:

sudo chmod 755 /var/www
sudo chown -R app_deployer /var/www/APPNAME
sudo chgrp -R deployments /var/www/APPNAME
sudo chmod -R g+s /var/www/APPNAME

This sets the /var/www directory back to world-accessible but NOT world-writable, ensuring that just the app_deployer user can make all the changes it wants to the APPNAME directory. (The “g+s” group-sticky-bit ensures that any new directories created under APPNAME carry the group owner too.)

Now, we’re getting close to deploying, but one thing we need to do is grant our production environment a way to clone our private repo. I logged out of the production terminal session and logged back in instead as the new user:

ssh -p 12345 app_deployer@www.coolapp.com

Then it was a matter of generating some RSA keys:

mkdir .ssh
cd .ssh
ssh-keygen -t rsa

After this I had a newly-minted id_rsa.pub. I turned to my web browser, went to Github, clicked on the Admin link on my app repo, then clicked Deploy Keys. There I created a new key and put up the contents of that public key.

Perfect. Now I can really do the deployment via Capistrano:

cap deploy

At this point messages scrolled by as the release branch was cloned from Github onto the production server into Capistrano-versioned directories. I did run into a couple of errors at first, but that was just because I had some issues with Git submodules. But I think this situation was more unique to me and it turned out in the end I had to juggle some RSA public keys to get things working.

Going Live With Apache+Passenger

(*One thing I didn’t mention was that I had actually done a previous deployment manually where I had SFTPed up my entire codebase to a temp directory and had done the database migrations already. Because of this I didn’t need to ask Capistrano to set up my database too—creating a user for this app, creating a MySQL catalog for the data, initializing the schema. It was also the case I got Passenger working with the test deployment.)

Setting up Passenger is really easy and there’s tons of guides saying how to do it on Linux. The essence of it is:

  • Make your Apache server is set up to handle its virtual domains (if you’re using them)
  • Make sure your Rails and Rubygems are all working first
  • Get the Passenger gem and follow all the instructions (which are really good, btw)
  • Put up a test app just to make sure everything’s working OK

Following the Passenger setup instructions there were a few lines that needed to be appended to the httpd.conf file. Instead I created a separate config file in the conf.d directory:

# passenger.conf

LoadModule passenger_module /usr/lib64/ruby/gems/1.8/gems/passenger-2.2.15/ext/apache2/mod_passenger.so
PassengerRoot /usr/lib64/ruby/gems/1.8/gems/passenger-2.2.15
PassengerRuby /usr/bin/ruby
PassengerMaxPoolSize 5
RailsEnv production

That config limits Passenger to 5 instances and ensures that the app is in Production mode. Next I added a config file for the new app:

# coolapp.conf

<VirtualHost *:80>
    ServerAdmin contact@coolapp.com
    ServerName coolapp.com
    ServerAlias www.coolapp.com
    DocumentRoot /var/www/coolapp/current/public
    <Directory /var/www/coolapp/current/public>
        AllowOverride all
        Options -MultiViews FollowSymLinks
        Allow from All
    </Directory>
</VirtualHost>

After a quick Apache restart the app came online w/out any problems, and now whenever I want to release to production all I have to do from my laptop is:

script/sync_master_to_release.sh
git push
cap deploy

Fast, responsive computing

I just read John Gruber’s The iPad Big Picture entry and the bit that caught my eye was:

But: everyone I spoke to in the press room was raving first and foremost about the speed. None of us could shut up about it. It feels impossibly fast.

That was very similar to my experience when I started using my Air. With this device it’s about as close to instant-on on any laptop I’ve ever had—from opening the clamshell to being able to do anything with it is less than a second. It’s just like pulling out a pad of paper to jot down some notes. I wouldn’t say that the Air is “impossibly fast” but I have to tell you that even though this computer is 1.8 GHz and my Pro is 2.5 GHz, it is an absolute pain to use the Pro now. By the time the Pro wakes up the thought I wanted to write down is gone.

The iPad is definitely something I’m considering now. It seems to fit my needs: I need a quick, responsive, digital device that can get me to my media, to my notes, to a command prompt so I can tweak servers, and enough pixels on the screen so I can read graphs and text. And if it’s hecka fast, well that just about sells me.

Are “find in project” searches in TextMate slow and eating up all of your CPU and RAM?

I was doing a casual project-wide search for some text yesterday when suddenly my computer ground to a halt. I opened Activity Monitor and saw that TextMate was taking up 2.42 GB of RAM. Yes, gigabytes. Not only that, the Find In Project searches were extremely slow.

I started poking around and found another blog entry dated April 27, 2006, and that gave me the answer. It turns out that TextMate will search all files it thinks are text, even if the files are binary files. And if you have a large project like mine then you’ll end up consuming all of your computer’s memory while it searches all of the graphics files and audio files.

textmate_treat_files_as_binary_1.png

TextMate’s way of ignoring binary files is for you to explicitly tell it that certain extensions are NOT text. How do you know what TextMate is thinking? Right-click/ctrl-click on a file in your project drawer and you should get the “Treat Files with ‘.png’ Extension as Binary” message when TextMate is searching those files. Try all of your .pdf, .png, .gif, .jpg, .mp3, .doc files.

textmate_treat_files_as_binary_2.png

Safari 4: Alternate tab grips?

The new grips on the tabs for Safari 4 are functional but to me they connote resizing rather than moving/tearing-off. The handle metaphor might be better but it probably would look ugly. So I was doing some thinking about suggesting “gripping” using something with traction nubs on them. Here’s a set: the original as is today, a wedge-type grip, and a spot-type grip.

saf4_alt_grips.png

Installing the Haml bundle for TextMate

This is more for my benefit of forgetting how to install the Haml bundle for TextMate. (Surreptitiously borrowed from Barry Hess’ blog entry.)

  1. Ensure your bundles directory exists:
    mkdir -p ~/Library/Application Support/TextMate/Bundles/
  2. Go to your user TextMate bundles directory:
    cd ~/Library/Application Support/TextMate/Bundles/
  3. Check out the bundle from Macromates:
    svn co "http://macromates.com/svn/Bundles/trunk/Bundles/Ruby Haml.tmbundle"