Feeds:
Posts
Comments

Archive for February, 2007

Dotfiles Best Practice

I’m a UNIX guy.

After years spent on using a myriad of flavors (*BSD, Linux, Solaris, Mac OS X), I can hardly go back to Windows. For me, the experience of going back to Windows is very similar to the experience of using UNIX to most people. It’s all about familiarity.

One reason why I find UNIX so productive relates to the customizations I’ve created for myself over time. I have customized bash (tcsh before) and vim to use everybody’s best tricks.

Unfortunately, I now live, day-to-day, on 4 different machines:

  • my iBook (Mac OS X)
  • my PVR (Gentoo)
  • my work laptop (Windows with many CentOS in VMWare)
  • several lab machines (CentOS–one account thanks to NIS and NFS)

I had not gone through the effort of synchronizing my environments, therefore my tricks were all over the place. My customization weren’t guaranteed to be present which resulted in me shying away from using them.

Today I hit my fill and decided to spend the time necessary to set my environments properly.

My life changed for the better after I read about Using Subversion to Maintain your Configuration Files. While I did keep my dotfiles in svn before I read the article, I was rather annoyed by the less-than-optimal setup. Now I can keep my dotfiles in ~/etc and symlink to them.

Here’s the content of my ~/etc directory:


# find . -type f -not -ipath '*.svn*'
./bash/aliases.sh
./bash/bindings.sh
./bash/local/aliases.sh
./bash/local/variables.sh
./bash_profile
./bashrc
./irbrc
./symlink_it.sh
./vim/after/ftplugin/ruby.vim
./vim/after/syntax/diff.vim
./vim/filetype.vim
./vim/ftplugin/html.vim
./vim/ftplugin/python.vim
./vim/ftplugin/ruby.vim
./vim/ftplugin/sql.vim
./vim/ftplugin/txt.vim
./vim/ftplugin/xml.vim
./vim/plugin/spacehi.vim
./vim/syntax/txt.vim
./vimrc

A few notes:

  • symlink_it.sh creates the symlinks to the versioned versions:
    
          #!/bin/sh
    
          cd ..
    
          ln -sn etc/bash .bash
          ln -sn etc/bashrc .bashrc
          ln -sn etc/bash_profile .bash_profile
          ln -sn etc/vim .vim
          ln -sn etc/vimrc .vimrc
          ln -sn etc/irbrc .irbrc
        
  • bash/local contains the shell scripts that are conditionally loaded to override the defaults (svn propset svn:ignore local bash). Here’s a preview of the relevant parts from my .bashrc:
    
          cond_source ()
          {
            if [ -f $1 ]; then
              source $1
            fi
          }
          
          cond_source "$HOME/.bash/local/variables.sh"
    
          cond_source "$HOME/.bash/aliases.sh"
          cond_source "$HOME/.bash/local/aliases.sh"
    
          cond_source "$HOME/.bash/completes.sh"
          cond_source "$HOME/.bash/local/completes.sh"
    
          cond_source "$HOME/.bash/bindings.sh"
          cond_source "$HOME/.bash/local/bindings.sh"
        

Now I just wish I had taken the time before…

Read Full Post »

I was catching up on my RSS feeds today when I stumbled upon this video. If, like me, you push through the initial skepticism, you’ll probably walk away rather impressed and/or inspired.

These guys managed to turn consultancy on its head. They are doing work they are passionate about without any compromises.

Here’s their philosophy in a nutshell, taken directly from the slides:

  • no contracts
  • no fixed prices
  • no functional specs
  • no employees
  • no code ownership
  • engage real users
  • don’t conform

Intrigued? Go watch it, I’ll wait. :)

That was a great presentation. However, no matter how much they believe in what they say, they only hold a part of a bigger truth. At this point, I would recommend you read Zed Shaw’s The C2I2 Hypothesis. This essay describe the axes of user involvement (C2) and complexity (I2) inherent to all software projects.

What the unspace guys are talking about is 1 of the 4 quadrants of software development: collaborators-inventions. They find customers who want to be 100% involved in the process. And they work on projects where what needs to be done is unclear—something new that will evolve during the lifetime of the project.

This is wonderful. This is where most passionate developers would want to be. They are, in effect, hitting the niche of people who give a shit.

Too many times, I’ve seen projects where the customers were seen as enemies. They didn’t really want to have a software system, it was a necessary evil imposed on them for very good reasons. These are the worst possible people to work with.

This reminds me of Paul Graham pre-Viaweb bsuiness, Artix. Trying to convince art gallery owners to put their collection on the Web. These people had no interest in technology . Viaweb was the opposite approach, trying to make websites for people who -wanted- to be on the Web. In the end, it’s not really about what you do, it’s more about your audience.

Swimming with the current is always easier than swimming against it.

Read Full Post »

Ruby Streams

I’ve been thinking about my business days problem some more. And this time I turned to Ruby, a language which I am becoming quite familiar with.

This is my naive implementation of streams in Ruby. Streams are thus functions. The actual class name is ‘Proc’, a lambda returns a ‘Proc’. Each call returns a new value.


def stream_from(value)
  lambda {value = value.succ}
end

class Proc
  def filter
    f = lambda do
          value = self.call
          return (yield(value) ? value : f.call)
        end
  end

  def take(n)
    result = []
    n.times {result << self.call}
    return result
  end
end

As for “filter”, it takes a predicate passed as block. The filter becomes a “decorator” for the stream.

This is a nice example of closures. The ‘value’ parameters becomes the state for the stream. Also of note, the use of the variable ‘f’ to fake recursion of an anonymous function.

Prints the 20 next business days:


s = stream_from(Date.today).
      filter {|date| date.cwday < 6}
puts s.take(20)

Note that my “contract” with stream_from is that what I pass it implements succ. Here’s an example with integer:


s = stream_from(4)
puts s.take(20)

And, of course, filters can be chained. The next Monday that falls on a 17th:


s = stream_from(Date.today).
      filter {|date| date.day == 17}.
      filter {|date| date.cwday == 1}
puts s.call.to_s

Here’s the same code as before, but with a function cast as a block:


def monday?(date)
  date.cwday == 1
end

s = stream_from(Date.today).
      filter {|date| date.day == 17}.
      filter(&method(:monday?))

I decided consciously to avoid optimizations here. It did keep my code short and clean. Besides, you should only optimize based on need.

There’s much more to streams… combining streams together, maps, more complicated generation of the next value, etc.

So, here’s your next interview questions:

“What’s the first 3 prime numbers after 5,000,000,000 which has a 3 as last digit?”


s = stream_from(5_000_000_000).
      filter{|x| x.prime?}.
      filter{|x| x.mod(10) == 3}
puts s.take(3)

I leave the code for “prime?” to your imagination.

The concept of command-line pipes springs to mind. One of the reason the command line is so powerful is that you can combine filters together to perform truly complicated tasks. Another reason is that each filter does only one thing and does it well.

It’s all about thinking in pipes.

Read Full Post »