Recapping 29 Days with Emacs

Before the beginning of the month of February, I endeavored to make February 29 days of exclusively using Emacs to edit code. I wanted to fully immerse myself in Emacs, and force myself to learn its ways. Why? I wanted to understand why people love it, including several friends. I wanted to truly know how it compares to my favorite editor, Vim. I wanted to make myself learn something new.

As you probably guessed, I was unable to exclusively use Emacs for the entire 29 days; I had to open Vim a few times when I felt like I was losing productivity at a time when I could not afford to be losing productivity. This really wasn’t a surprise. I knew trying to stop Vim “cold-turkey”, and replace it with Emacs, would leave me sweating, twitching, and pining for Vim.

That said, Emacs certainly has features that I liked.

Pros before Noes

Self-bootstrapping

I tell Emacs what packages I want to definitely be there, and it ensures those packages are present using ELPA and, in my case, Marmalade. The necessary lines in my config look like this:

(require 'package)
(add-to-list 'package-archives
  '("marmalade" . "http://marmalade-repo.org/packages/") t)
(package-initialize)

(when (not package-archive-contents)
  (package-refresh-contents))

(defvar my-packages '(starter-kit starter-kit-ruby starter-kit-js js2-mode haml-mode php-mode css-mode markdown-mode)
  "A list of packages to ensure are installed at launch")

(dolist (p my-packages)
  (when (not (package-installed-p p))
    (package-install p)))

Superior File Finding

Emacs' “default” method of searching for files is superior to Vim’s. Its auto-complete is better, its matching is better (slightly fuzzy?), and it seems faster. I hate navigating to files using :e in Vim. It is my least favorite aspect of Vim. (I also hate project drawer plugins, and PeepOpen is too slow, and not integrated enough, for my tastes. Let me know if there’s another plugin that I should use.) There’s a plugin for Emacs, textmate.el, that further enhances this (though it uses a different shortcut by default) by restricting it to the project you’re in. I sometimes like this, and sometimes I don’t. Thankfully, I can use both. The plugin textmale.el adds a few other things I like, actually. I was surprised by it. Of course, Chris Wanstrath wrote it, so my surprise was naivety, or maybe just stupidity.

Syntax Checking

This is a bit weird for me. I mean, I would normally argue that I don’t need syntax checking, I don’t need an IDE, I don’t need all that bloat. I would still normally make that argument. However, February wasn’t normal. I have been doing a lot of PHP work. Too much PHP work. Well, any PHP work is too much, but you get the point. PHP makes me stupid, somehow. I end up writing awful code. I end up missing parens and single-quotes and double-quotes and brackets and semi-colons and — if there is a bit of required syntax in PHP, you can bet I’ll figure out a way to forget it or fuck it up. Someone should study me as I write PHP, then study me writing Ruby or Javascript, and then explain to me and the world what about PHP makes me imbecilic.

Using flymake-php, I was able to cut down on those stupid mistakes. I’m not sure it’s always useful, but it was useful in this case.

I actually wrote some elisp to run CoffeeScript through CoffeeLint upon a particular key-chord. It’s not very good, my code, and it isn’t using Flymake. However, it’s a testament to …

Elisp/Extensibility

Elisp is better than VimL, in my limited experience, but I think even people who write a lot of VimL would agree there. Emacs is fairly obviously more extensible than Vim. To be fair, Emacs and Vim have different philosophies — Vim doesn’t want to do all the stuff that Emacs does. Because I dig the idea of simplicity/minimalism/focusing on a few things and doing them really well, I feel some kinship with Vim. In practice, I own a lot of stuff I don’t need, and I try to do far too many things to truly excel at any single one. There’s a good chance Emacs and I are actually more alike.

Noes

Paper Cuts

“Paper cuts”, as in “death by a thousand”, is the best label for the bucket that holds all the small complaints I have about using Emacs. Individually, they aren’t significant; they are but a small cut on a finger tip. Collectively, holy shit balls, my hands hurt. Getting Ruby indentation the way I want it was a pain. Actually, getting to a specific line in a file annoys the piss out of me every single time I do it, and I do it a lot. Perhaps most people don’t navigate files the way I do, but M-g M-g 65 RET is infuriating when compared to 65G.

I think Ross Baker said it best when he said: “Emacs: Hard things made possible. Easy things oftentimes made hard.”

That sums up Emacs' primary negative, for me. It does leave me with the feeling that I can get Emacs to a point of perfection if I keep trying, though.

Lacking Modal Editing

Of course, M-g M-g 65 RET is merely a side-effect of Emacs not doing modal-editing out of the box. Vim is the modal editor, and that is all it does. Naturally, it is magnificent, if you like that sort of thing. Guess what? I do. I really, really do. Using Emacs (in lieu of Vim) for 29 days did more to convince me that modal editing is the most efficient way to edit text than several years of Vim use. When I completed a task quickly with Vim, after getting frustrated trying to get things done with Emacs, I felt like I needed to smoke a cigarette. Oh yeah, modal-editing. Mmm, yeah.

So, It’s Over?

I really have been using Emacs every day. In fact, it’s open as I type this, with some code from a client’s Rails project in the open buffer. I intend to continue using it in March, even though I can let myself off the hook. However, I do intend to install and use Evil, which grants some modal-editing abilities. I had barred myself from that crutch up until now. I will let you know what I think of it.

I also intend to write a post, at the risk of inciting the next battle in the war, with my view of Emacs versus Vim. Preview: they’re both great.

Force-feeding Myself Emacs

I am a Vim guy. I run the @vimtips Twitter account. I have given Vim presentations. I maintain a couple Vim plugins (kinda). I have cultivated a list of various helpful Vim links. My point is that I really like Vim. I might even love it. Who am I kidding? I definitely love Vim.

However, I am going to use Emacs every day for the month of February.

I want to challenge myself. I want to learn more about Emacs. I want to understand why so many of our industry’s elites have, in the short history of computer programming, loyally and sometimes fanatically used Emacs. I want to have a little fun.

Thankfully, I know several people using Emacs. I asked for some advice as to how to hit the ground running on February first (via Twitter, among other means). In case you would like to try Emacs also, I thought I would document the helpful suggestions I received.

Suggestions for Getting Started

Five people responded (@tihm, @kyleashipley, @gregors, @damionjunk, and @mediocretes). Four of them recommended the Emacs Starter Kit. That sounds like a ringing endorsement!

Damion also suggested installing Emacs 24 via Homebrew (as I’m on a Mac). That lead me to the article Emacs 24 Rails Development Environment – From Scratch to Productive in 5 Minutes, from which I expect I’ll rip some ideas.

Nate (mediocretes) also suggested his fork of Expected Behavior’s common-files, and added “now with twittering-mode” which sounds both wonderful and awful.

Of course, there is Emacs' Vim Mode. I will have to try that before February has run its course.


That seems like a pretty good start. I hope. I would like to learn a little elisp, and write an extension perhaps, but I doubt I’ll get that far.

Wish me luck. If nothing else, by the end of the month, I will at least be able to say I’ve been, albeit temporarily, on both sides of the Editor War.

Combining FactoryGirl's Generated Files into One

If you are using Thoughtbot’s FactoryGirl in a Rails 3 app, you are probably accustomed to the library generating a new file per factory/model it generates. You end up with something like this:

$ ls test/factories
 things.rb other_things.rb more_things.rb omg_things.rb

I really dislike it generating a file per factory. I prefer one file in which I can see each factory I will be using in my tests. I am, evidently, the odd man out. I dug around the Interwebs a bit, unsuccessfully. This led to me fixing it myself witha Rake task:

namespace :factories do
    desc 'Combine individual factory files into a single file'
    task :combine do
        File.open(File.join(Rails.root, 'test', 'factories.rb'), 'a') do |f|
            Dir.foreach(File.join(Rails.root, 'test', 'factories')) do |factory|
                next if factory == '.' or factory == '..'
                full_path = File.join(Rails.root, 'test', 'factories', factory)
                text = File.read(full_path)
                f.write(text)
                puts "Removing #{full_path}..."
                File.delete(full_path)
            end
        end
        puts "Removing the factories directory..."
        Dir.rmdir(File.join(Rails.root, 'test', 'factories'))
        print "Done."
     end
end

I run that whenever I have generated a new model or resource (and thus a new factory file).

Using ZSH to Rename in Rails

At the Indy.rb Code Review Session (11-30-11), Dan Doezema asked if there was an easy way to rename a resource, or the related model, controller, view directory, tests, and potentially factory or fixture. We had a good laugh after someone mentioned that being one of the features that lure people to try Smalltalk, or, perhaps, the Ruby VM MagLev. The joke is that doing either of those two things is very likely a road to compromised mental health.

A Christmas Miracle!

This renaming issue was on still bouncing around inside my mind as I began reading the first day of this ZSH-focused advent calendar. Hey, look at that! Between day one and day two, one can piece together a nice line for renaming the files related to a resource in Rails.

$ cd project_root
$ zmv '(**/)old_name(*)' '$1new_name$2'
$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add/rm ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#   deleted:    app/controllers/old_names_controller.rb
#   deleted:    app/models/old_name.rb
#   deleted:    app/views/old_names/new.html.haml
#   deleted:    test/unit/old_name_test.rb
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#   app/controllers/new_namess_controller.rb
#   app/models/new_name.rb
#   app/views/new_names/
#   test/unit/new_name_test.rb
no changes added to commit (use "git add" and/or "git commit -a")

Santa’s Little Helper

That is only half of the problem, though. In fact, it’s arguably the easier-solved of the two halves, whether you use Bash, ZSH, or something completely different. How are we going to edit the content of the files? After the above command, we’re still stuck with this:

$ vim app/models/old_name.rb
class OldName < ActiveRecord::Base
  # ...
end

More command-line work to the rescue!

$ git ls-files --other --exclude-standard | xargs sed -i '' 's/OldName/NewName/'
$ vim app/models/old_name.rb
class NewName < ActiveRecord::Base
  # ...
end

Great! Two lines of terminal work and we’ve reached our goal!

Good Enough

This isn’t perfect. You still might have to change other references to the class, such as a has_many :old_items line in another class, or something similar. If you have a better method you’ve been employing (short of installing an IDE), I would love to hear it!

Y U NO LIKE VERGE

Today, Anthony Panozzo mentioned Verge’s new “qualifying question” policy, in which you essentially must be a startup employee or founder to attend. I seemingly took that opportunity to pile on Verge, like some kind of entitled asshole. That wasn’t my intention, I swear! At least, it wasn’t consciously my intention. Let me clarify.

Quick aside: Matt Hunckler and company have put in good, hard work on this event. I do not mean to disparage him, others who helped, or those who attend. I am not saying the event isn’t a worthwhile event. SPOILER ALERT: I’m saying it’s not my thing, basically.

Living in an Alternate Reality

Verge used to be called Hackers & Founders. Unfortunately, calling an event Hackers & Founders creates a set of expectations. Let me quote from the original Hackers & Founders site:

It’s mostly a chance to get together with hackers who are founding or are interested in founding startups. Many of us hang out at Hacker News. So, if you’re in the area and interested in chatting with people of like mind, please stop by. We’d love to get to know you.

… and, from the description of a recent meeting:

Topics of conversation include hackery in general, startups, shiny new technologies we’re playing with, recent articles on Hacker News and miscellaneous cool stuff.

That is what I expected when I first attended a meeting. It wasn’t quite that, but it was fairly casual, and in the back of a bar/restaurant. It had an intimate feeling to it.

I think I probably should have, both in this instance, and in general, a more open mind. I think there is a good chance I went in wanting Mountain View’s Hackers & Founders, and I wasn’t willing to settle for less.

Love What You Got

I wanted to like Verge, and attended a couple other events. I had a fine time. I mean, beer, a festive atmosphere, Earthhouse, excited people… it’s easy to enjoy. Afterward, however, I always felt like the event wasn’t really for me. I also felt that I should continue to support the thing, because it’s good for Indy. (Of course, then I opened my big mouth / typing fingers on Twitter today.)

It’s hard to explain what about Verge didn’t hit the groove for me. Again, I think it’s because I was still wanting Hackers & Founders. I wanted, “Man, we’re using Node.js to build this awesome real-time client-smiting application. Yeah, it’s evented as hell!” … uh, or something. Instead, it is more high-level, more business-y, more network-y, more… more…? Seriously, I am not sure I can properly articulate my problem.

You Don’t Need Me

When Anthony and Kyle Shipley began discussing Verge, and the qualifying question policy, this morning, I jumped up to say I didn’t like this incarnation of Verge, basically. You can start with this tweet, if you’d like to read more. Also, read this blog post from Anthony.

Anthony, in that post, says that this makes Verge more interesting for him. It essentially targets him directly, now. That is a good thing! Someone feeling like Verge is more relevant is, I’m sure, exactly what Matt was going for. That it also excludes people fairly directly is also what Matt was targeting. Matt is always really nice to me, even when he explicitly invites me to stuff and I don’t attend. I am guessing he wasn’t expecting that I would feel excluded. Still, it’s a good thing. Creating a group who feels explicitly included is important. Excluding people is an acceptable consequence, I think. You don’t need me. You need the Anthonys, Matt Gordons, Kyle Shipleys, etc.

What About Hackers & Founders

Does this leave space open for a new meeting that is in the spirit of the original Hackers & Founders? I think so. I have a serious question for those who might be interested, though. Does the Indy Hackers Bar Meet do that sort of thing already? Once a month we get together at a bar and chat over beers and food. The biggest difference I see is that I have never made Indy Hackers even almost focused. A few of us talked about posts on Reddit last time — we’re talking poorly drawn comics and dumb pictures with dumber captions. However, we also talked about what we’re doing at/for work lately, etc. The Venn diagram would be a huge circle labeled Indy Hackers Bar Meet Topics, with a little circle inside it labeled Hackers & Founders Topics. Is a combination of the Indy Hackers Bar Meet and Indy.rb, Indy.js, et cetera, good enough?

I don’t want to change Indy Hackers Bar Meets. So, what do you think? Do we need a Hackers & Founders meeting, in the same vein as Mountain View’s Hackers & Founders?

Deprecation warnings for proxy_owner in Rails 3.1

In Rails, you are used to doing something like this:

has_many :assignments do
  def root
    proxy_owner.assignments.where(:ancestry => nil).first
  end
end

This way, if you call parent_record.assignments.root, the root method acts on the array of assignments that belong to that parent. It’s nice. However, in Rails 3.1 you will see a big scary message in your logs, or in your test output.

DEPRECATION WARNING: Calling record.assignments.proxy_owner is deprecated. Please use record.association(:assignments).owner instead. (...)

I will admit that it is not very frightening, actually. It is mostly merely annoying… annoying as hell. Get out of my test output!

The working solution that I found looks like this:

has_many :assignments do
  def root
    @association.owner.assignments.where(:ancestry => nil).first
  end
end

This functionality is now defined in collection_proxy.rb, which was quite a bit of help in finding this solution. Bid those deprecation warnings adieu!

PS – I do not know whether this is the core-team accepted solution. I am certainly happy to see a better one!

Learned or Re-learned in My First 60ish Days as a Freelancer

Though it’s only been 60ish days [1], I have finished a few projects,some done well, maybe one done not-so-well. As I have battled my way through the fog of war, I think I have learned a few things worth mentioning. I have learned where I stand on the issue of payment: hourly or fixed-bid — with one possible exception. I re-learned that over-communicating is better than under-communicating. Finally, maybe most importantly, I learned that even when you lack any motivation to get things done, you can get things done.

Now, this isn’t all I learned. Freelancing has already been fantastic for my education and evolution as a developer. These are the notable,might-be-fun-to-discuss things. On to the show:

Fixed Bids > Hourly Work…

After 60ish days, I’ve decided a fixed bid is better than an hourly arrangement. One pro is the customer knows how much it’s going to cost beforethe project starts, which, it seems to me, typically results in a more comfortable customer. When the customer is more comfortable, I am more comfortable. Surprises can be fun, but not so much surprise invoices. Another check in the fixed-bid column is I can require 50% of the project’s cost upfront, which makes me happy, confident, comfortable, and excited to get started on the project.

I also enjoy the opportunity to attempt to “beat” my bid. In other words, I want to be more efficient than I thought I could be when I made the bid. I want to win. I want to deliver the same high quality final product the customer expects more efficiently than I thought I would. I think people call that a WIN/WIN. This is the primary reason I like fixed bid projects.

That said…

Except When Things Goes Awry

When a project is in a bad way, piling up like so many cars on a busy freeway, it’s easy to think “clearly I should only do hourly arrangements because: Wow! This sucks.” This is an obvious reaction, but, man, it is strong. It can also further sap your motivation, your gumption, as you begin resenting every hour you’re spending on that project. However, the things you can learn on a Pile-Up Project constitute a whole post of their own. A Pile-UpProject is a great chance to learn things that will be useful inwinning the next project.

So, forget it, fixed bid is still the greater.

Over-communicating is Way Better Than Under-communicating

Not asking questions that need answered, assuming an answer to a question you didn’t ask, and worrying about being annoying by asking too many questions are all things that I should not do. I know those. I knew those. I must have forgotten those. I re-learned them in the past 60ish days. You know a sure-fire way to create a Pile-Up Project? Do those things. Man, I’m angry about this. It doesn’t matter how many times it happens, I hate realizing I am repeating mistakes. Hate it. What is the consequence of over-communicating? What is the consequence of annoying someone? If the project gets done well, they’re going to forget they were annoyed. They might even be stoked about it. Over-communicate. Just… over-communicate. Honestly, it is easy.

I Can’t Always Be Motivated to Get Stuff Done, But I Can Always Get Stuff Done

I do not always sit down at my desk anxious to begin the day, excited to work on what it is that I need to work on that day. Some days, I don’t want to even think about the project about which I must absolutely think that day. You can’t always have that gumption [2]. You can always get stuff done, though. It’s difficult, and I’m not great at it. It is most difficult when I’ve just poured my coffee, opened my laptop, and realized I’ll probably have to put in 12 hours that day. Shit. If I don’t do something simple, like grab an index card and write down a list of things I need to get done, the day could go quite poorly. You know what I do every morning now? I grab a freakin' index card and write down what I need to get done.

I Cannot Wait to Learn More

I think I have learned some valuable things, and I am very excited to learn more in the next 60ish days. I suspect that freelancing is an incredibly effective way to learn stuff, as it is very much a classic “sink or swim” situation, a trial by fire, probably yet another cliché that I cannot recall at the moment. Maybe the most important nugget, though, is that it is a lot of fun.

[1] – It’s been more than 60 days now, but this essay was conceived at around day 63.

[2] – I am warming up a post about Zen and the Art of Motorcycle Maintenance, which speaks to gumption (approximately motivation) and its blockers.

Thank you to Dave Jones and Mike Rogers for reviewing, critiquing, and helping me to revise this essay.

DataMapper, Rails 3, and Multiple Databases

DataMapper is awesome. It’s flexible, you define the properties in the model itself, it deals with all sorts of columns, it can create UUIDs easily, it is fantastic for dealing with legacy, or just not designed with Rails’ ActiveRecord in mind databases. Hell, it shoveled my driveway, hooked up my cable, and delivered our beautiful, 7 pound, 2 ounce baby boy last Tuesday. (I kid! I don’t have a baby. Yet.)

It can also connect to multiple databases, even when used as the ORM in a Rails 3 app. Unfortunately, this isn’t mentioned on DataMapper’s website, that I could find. However, people with their wits about them (I am not in that set of people) might think to check out the README for the dm-rails project on Github. In there, it shows how to lay out your database.yml properly. It’s important. Go see it. Go. I’ll wait.

I mention this, and forced you to go look, mostly to help someone searching frantically. You there. Guy who has been searching for this frantically in futile frustration for an hour: Your journey is over. Let’s move on.

I had to do a bit of work to get RSpec and Cucumber behaving correctly. I want my test databases, or repositories, cleared after each test. I solved RSpec first, so we’ll start with that. My spec/spec_helper.rb looks something like this:

ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'

Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

RSpec.configure do |config|
  config.mock_with :rspec

  config.before(:each) do
    DataMapper::Model.descendants.each do |model|
      DataMapper.repository(model.default_repository_name).adapter.execute("SET foreign_key_checks = 0")
      DataMapper.repository(model.default_repository_name).adapter.execute("TRUNCATE TABLE #{model.storage_name}")
    end
  end
end

Clearly the code above is specific to MySQL. If you’d rather avoid shackling a specific database server to your app’s ankle, you might try something like database_cleaner.

The interesting part is probably DataMapper.repository(model.default_repository_name). I define self.default_repository_name differently for models that aren’t using, well, :default. That allows this to work (among other things in DataMapper). I recommend it. For instance:

class SecondaryUsinThing
  include DataMapper::Resource

  def self.default_repository_name
    :secondary
  end
  ...
end

I needed Cucumber to do some of this crazy junk also, of course. The dm-rails gem recommended a before and after block to add to a features/support/datamapper.rb, but I had to add a bit to mine to make it work.

Before do
   DataMapper::Model.descendants.each do |model|
     DataMapper.repository(model.default_repository_name).adapter.execute("SET foreign_key_checks = 0")
     DataMapper.repository(model.default_repository_name).adapter.execute("TRUNCATE TABLE #{model.storage_name}")
  end
  [:default, :secondary].each do |repository|
    DataMapper.send("repository", repository) do |repo|
      transaction = DataMapper::Transaction.new(repo)
      transaction.begin
      repo.adapter.push_transaction(transaction)
    end
  end
end

After do
  [:default, :secondary].each do |repository|
    DataMapper.send("repository", repository) do |repo|
      repo.adapter.pop_transaction.rollback rescue nil
    end
  end
end

Familiar, right? That should get your testing mojo rising. It’s basically opening the door for DataMapper, so he can come in and repaint your nursery while teaching your newborn sign language, or one of his many other talents.

Checking all Checkboxes with Capybara

This could be useful to someone searching the Interwebs for a solution. Hopefully it will save someone some time, as it took some time to figure it out. Looking back, I can see where someone might find it obvious. I didn’t, for some reason.

The following is how I accomplished it, using a CSS selector:

When /^I choose all of the damn checkboxes$/i do
  all('li.checkboxes input').each {|ch| check(ch[:id]) }
end

This requires that the checkbox input elements have a unique id attribute. You might, having some knowledge of Capybara’s Element class, think that you can just use #path, which returns an elements XPath string, in place of [:id]. That’s what I thought, and I welcome you to try it — what kind of hackers would we be if we believed it every time someone said something wasn’t possible? I, unfortunately, was unable to make it work. The check method reported that it could not find an element with said path (or XPath).

I’d love to hear it if you have better luck!

Posterous theme by Cory Watilo