Wednesday, March 24, 2010

Don't .gitignore database.yml

Generally, you put into .gitignore stuff that has the following characteristics:

  1. Transient artifacts of the development/testing cycle that have no enduring or shared value (e.g., log/*.log, db/*.sqlite3, tmp/*).
  2. Artifacts that are purely derivative (e.g., doc/api--I don't know that these are purely derivative; I assume that the contents of this folder are generated by some rake doc fu and that is why this and some other doc subfolders are typically .gitignore'd).
For the above, you really have to contort yourself to find a good reason to put these things into shared source control. And there are clear and obvious downsides to putting them into source control. At best, it's merely confusing and generates needless churn in your repository.

So I was confused when I heard someone casually defend the inclusion of database.yml in the set of things generally included in .gitignore.

Here are the reasons I've heard for keeping it out of the repository:

Individual Preference



Each developer might have their own conventions, preferences for the database (e.g., you like MySQL, I like PostgreSQL; we can just get along).

My perspective is that for any relatively small team-based development, we should pick a tool and use it. Why ever spend anytime on database differences that add no value to what we're trying to accomplish? Does the opposite apply for larger team development? I doubt it. I just don't have a whole lot of useful experience with that type of development. It'd be interesting to hear people with that perspective speak to this. Have you gotten value out of promoting, fostering the "everyone roll your own database.yml" dance?

It's the same thing with editors. Yeah, it seems democratic in a good way to promote pick-your-own-editor. On the other hand, imagine a team that all learns a tool really well. They can share that knowledge with each other. And there's synergy that comes from that.

Security of local development database concerns



The preferences might extend to a continuum of security-centric preferences (e.g., you think username=postgres is the way to go with local trust; I think I need to have a super cryptic password so no one can hack my local database).

I tend to think that setting up your database server so that it only listens locally is generally good enough for me. Do you work with people who think otherwise? Are their concerns legitimate? I'd love to hear real experience related to this.

Security of production credentials concerns



You might have production credentials in database.yml, so adding it to .gitignore keeps those credentials safe.

Um, seriously? Your production credentials are sacrosanct and yet sitting in developer's working directories? It's hard to take this seriously. It's trying to play both sides.

Summary



This is why I recommend people reconsider adding database.yml to .gitignore.

The practice adds no obvious value. It confuses the point of .gitignore and promotes a do-it-your-own-way type of thinking that counteracts the virtue of leveraging conventions in the context of team-based development.

Thursday, July 2, 2009

Multiple Versions of Rails

I wanted to know whether you can have multiple versions of rails and found this helpful article.

SysInternals ZoomIt

One of the Epic presenters was using various Sysinternals tools during his presentation. These tools are super handy--I've used several of them over the years. But I didn't know about ZoomIt:

ZoomIt is screen zoom and annotation tool for technical presentations that include application demonstrations. ZoomIt runs unobtrusively in the tray and activates with customizable hotkeys to zoom in on an area of the screen, move around while zoomed, and draw on the zoomed image. I wrote ZoomIt to fit my specific needs and use it in all my presentations.

Ruby equivalent to Python's getattr

I was looking for the Ruby equivalent to getattr and I ran into this article:

http://stackoverflow.com/questions/786412/what-is-the-ruby-equivalent-of-pythons-getattr

The answer was not generic enough for me. I'd like to implement a Ruby equivalent to Python's built-in sorted function.

So after a little more searching, I found the answer: send and posted it.

Wednesday, July 1, 2009

Playing with Ruby

I know Python very well. But it's helpful for me to reflect a little deeper on what this actually means. I don't use Python when I want to write a web app. I use Python when I have to manipulate and/or analyze files or text.

I don't currently have anything like mastery of a very effective and contemporary tool for writing a web app. This is why I'm interested in digging into Rails. And therefore why I need to dig into Ruby...

So I had this little problem: Create a drop-down list of the hours of the day, using "midnight" and "noon", but otherwise the 12 hour clock name (e.g., 1 AM, 1 PM, etc).

Ignore the drop-down list for a second and let's just focus on the data.

In Python, that would look something like this:


hours = dict([(hour, display(hour)) for hour in range(24)])
for hour in sorted(hours):
text = hours[hour]
print "" % locals()


"display" here is a function that takes a number (0-23) and returns a string. This is the least important aspect of this problem--probably because I'm more focused on learning how to iterate in Ruby, what the built-in stuff is capable of, etc.

Nonetheless, a simple implementation of display:


def display(hour):
if hour == 0:
return 'midnight'
if hour == 12:
return 'noon'
ampm = hour > 12 and 'PM' or 'AM'
return '%d %s' % (hour % 12, ampm)


In Ruby, I first tried this:


hours = (0..23).inject({}) do |hash, value|
hash[value] = display(value)
hash
end


inject is a cool little function. The problem here is that simple sorting is somewhat verbose in Ruby--at least, as far as I know. Here's what I came up with:


hours_sorted = hours.keys.sort_by {|k| k}.map {|k| [k, hours[k]]}

hours_sorted.each do |k, v|
print "\n"
end


That's when I realized, wait a second, why not just inject into an Array instead of a Hash?


hours = (0..23).inject([]) do |list, value|
list.push([value, display(value)])
list
end


Cool, now I have something I can iterate over simply:


hours.each do |k, v|
print "\n"
end

My Blogger Template Blows

It's too thin. I really don't want to fix this now--even if it's super easy.

Installing Rails on Tiger

I had an aborted attempt last year (late January, 2008) to learn and use Rails. My buddy Phil and I spent a long weekend down in Jacksonville with Jon and Jim. It was a whirlwind weekend. I learned a lot, had a lot of fun, but Phil and I decided to use ASP.Net/C# instead for the CCAP-based services.

I figured I'd come back to Rails, eventually. And that time has come.

My MacBook still had the 1.2x (was that what it was?) version of Rails that Jon helped me install. So when I was casting about for some help in installing a more recent version, I ran across this classic:

Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X

And I figured I'd put the whole thing into a single bash script (see below). The script has obvious deficiencies. It's not very parameterized. I comment out the function calls at the bottom that I don't want to run--rather than having the script detect when a component is installed or where the version installed matches the to-be-installed version.

Despite these deficiencies, it was useful for me both in setting up Rails this time and in serving as a record of what I installed.



#!/bin/bash
#
# install_rails_stuff

function install_readline
{
pushd /usr/local/src

if [ ! -f readline-5.1.tar.gz ] ; then
curl -O ftp://ftp.gnu.org/gnu/readline/readline-5.1.tar.gz
fi
if [ -d readline-5.1 ] ; then
rm -fr readline-5.1
fi
tar xzvf readline-5.1.tar.gz
pushd readline-5.1
./configure --prefix=/usr/local
make
sudo make install
popd
}

function install_ruby
{
pushd /usr/local/src

if [ ! -f ruby-1.8.6.tar.gz ] ; then
curl -O ftp://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz
fi
if [ -d ruby-1.8.6 ] ; then
rm -fr ruby-1.8.6
fi
tar xzvf ruby-1.8.6.tar.gz
pushd ruby-1.8.6
./configure --prefix=/usr/local --enable-pthread --with-readline-dir=/usr/local --enable-shared
make
sudo make install
sudo make install-doc
popd
}

function install_sqlite3
{
pushd /usr/local/src

if [ ! -f sqlite-amalgamation-3.6.16.tar.gz ] ; then
curl -O http://www.sqlite.org/sqlite-amalgamation-3.6.16.tar.gz
fi
if [ -d sqlite-3.6.16 ] ; then
rm -fr sqlite-3.6.16
fi
tar -zxvf sqlite-amalgamation-3.6.16.tar.gz
pushd sqlite-3.6.16
./configure --prefix=/usr/local
make
sudo make install
popd
}

function install_rubygems
{
pushd /usr/local/src

if [ ! -f rubygems-1.3.4.tgz ] ; then
curl -O http://files.rubyforge.mmmultiworks.com/rubygems/rubygems-1.3.4.tgz
fi
if [ -d rubygems-1.3.4 ] ; then
rm -fr rubygems-1.3.4
fi
tar xzvf rubygems-1.3.4.tgz
pushd rubygems-1.3.4
sudo /usr/local/bin/ruby setup.rb
popd
}

function install_rails
{
sudo gem install rails --include-dependencies
}

function install_mongrel
{
sudo gem install mongrel --include-dependencies
}

function install_capistrano
{
sudo gem install capistrano --include-dependencies
}

function install_termios
{
sudo gem install termios --include-dependencies
}

install_readline
install_ruby
install_rubygems
install_rails
install_mongrel
install_capistrano
install_termios
install_sqlite3