Feb 24, 2008

Marketing Open Source

Zed Shaw gives a talk about Mongrel where he touches heavily on how to market an Open Source project. It's worth watching if these things interest you at all, at the very least you'll learn what yak shaving is.

http://www.infoq.com/presentations/zed-shaw-mongrel-loc-economics

Feb 23, 2008

Patch Bombing and Change Stashing

I ran across the term 'patch bombing' today, which could be defined as; "multiple application logic changes all rolled into a single source code commit", it's the opposite of an 'atomic change'

I found the term relevant to a background thought I've been pickling over lately....

It's not uncommon for me to be in the middle of adding a new feature when I run across a bit of crufty code that needs to be refactored. Which poses the problem; How do I do the refactoring with out mixing the change sets?

In the past I'd just make both changes and write one fat commit message explaining everything but I always thought this approach smelled bad. Then, Jay Fields blogged about 'using patch as subversion's stash' and turned me on to 'the power of git-stash'.

It turns out that Bazaar, which I'm using for my current project, doesn't directly support this operation either but Jay's patch-stashing approach works just as well for bzr as it does for svn.

Feb 22, 2008

Method Not Allowed

Quite a bit of my old code just redirects when an action gets a request with an unsupported method, for example; 'get' requests to 'destroy' actions. While my old approach prevented anything bad from happening it always seemed wrong. It also made maintaining my tests a tiny bit more complicated because each seemed to have a different location they redirected to.

So I decided to clean up the code in my current project today. The obvious choice was to render an error template and return the proper status code.


# file: app/controllers/parts_controller.rb
def destroy
unless request.delete?
render :layout => false, :template => "errors/405", :status => 405
return
end
begin
Part.find(params[:id]).destroy
flash.now[:success] = "The part has been successfully deleted."
rescue
flash[:failure] = "Unable to delete part."
end
end
This also simplified my tests.

# file: test/functional/parts_controller_test.rb
def test_destroy_get
get :destroy
assert_response 405
assert_template("errors/405")
end

Feb 10, 2008

The Application Appliance

This post is the continuation of a thread that started with: Opportunities

The hardware it's self would not be remarkable in anyway and since I'm really only interested in the software stack the logical choice is to resell some other vendors machines preconfigured to meet my needs.

At this point I'm not exactly sure who's machines I'll use but I'd prefer it to be a vendor that sees Ubuntu (or maybe Debian) as a first class target. My short list at the moment really only contains System76 so if anyone has any other suggestions I'd love to hear from you?

The software on the other hand is much more interesting. The software will be delivered through a private apt repository as customized packages and include specifically configured base tools such as Apache, Postgres and Ruby as well as management tools for deployment, monitoring, replication and backup.

Now obviously there's nothing special about this approach, in fact that's kind of the point. I don't want to have to re-think the simple standard parts I want to focus on the newer more unique parts. The management tools, replication and fail over to cloud services, etc...

More later....

Feb 2, 2008

My Opinionated Application Stack

This post is the continuation of a thread that started with: Opportunities

Recently I've been thinking a lot about different ways to minimize duplication of work. Many of my projects have similar requirements, how best can I reuse the effort from one to the next?

I've also been puzzling over another problem; How do I provide businesses with reliable application when they don't have the necessary I.T. support to manage it and they don't have a reliable enough internet connection to go the "software as a service" route?

It turns out that both questions may have the same answer. An application appliance! A low cost plug and play application server that's configured with a well defined software stack and the ability to backup to a remote service that is able to double as a warm standby in a pinch.

In future posts I'll explain in more detail.

Opportunities

A driving belief of mine is that there's an enormous long tail associated with the custom business software market. It exists because software development is difficult and in the past only the deepest pockets have typically tried to tackle the problem but I think this has already began to change! Things like agile test driven development methodologies, the use of free software, and opinionated design are going to make it a reality.

I'd like to share my recipe for this but you'll need to keep in mind I'm focusing on the really (really) small business that just doesn't register on the radar of more established custom software providers.

It's really simple and goes something like this...

Stick to the small projects that can be completed quickly. Every business has itches that need to be scratched. Keep the customer involved, which should be easy if you're focusing on a real itches and provide a turn key (nearly) zero administration solution.

Which gets me to what I wanted to talk about, my opinionated application stack

Feb 1, 2008

My Apache Setup

I've been using Apache2 with mod_fcgid for quite a while because it's good enough. I use it primarily because it's really simple to administer and I'm hosting internal business applications with very little load on them. Here's my setup...

Installation is really straight forward

$> sudo apt-get install apache2 libapache2-mod-fcgid
$> a2enmod fcgid


default config
# serve everything from /var/www/ and use /var/www/default as the document root

ServerAdmin webmaster@hostname

# setup logs
ErrorLog /var/log/apache2/error.log
CustomLog /var/log/apache2/access.log combined
LogLevel warn\

# limit the amount of info about server
ServerSignature Off

# default permissions to all files
<Directory />
Options FollowSymLinks
AllowOverride None
</Directory>p;

# setup document root and permissions
DocumentRoot /var/www/default
<Directory /var/www/default>
Options +FollowSymLinks +MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>

# define environment for fcgid processes
DefaultInitEnv PATH "/opt/ruby/bin"
DefaultInitEnv RAILS_ENV "production"


per application config
# run the app from /var/www/appname and serve it aliased as http://hostname/appname

Alias /appname "/var/www/appname/current/public"
<Directory /var/www/appname/current/public/>

Options -Indexes +MultiViews +FollowSymLinks +ExecCGI
AllowOverride None
Order deny,allow
Allow from all

RewriteEngine On

# provide support for cap deploy:web:disable
RewriteCond /var/www/appname/current/public/system/maintenance.html -f
RewriteCond %{SCRIPT_FILENAME} !maintenance.html
RewriteRule ^.*$ /appname/system/maintenance.html [L]

# standard rails rewrite with support for alias directory
RewriteBase /appname
RewriteRule ^$ index.html [QSA]
RewriteRule ^([^.]+)$ $1.html [QSA]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]

# define error documents
ErrorDocument 500 500.html
</Directory>

Jan 26, 2008

Setting Up A Shared Bazaar Repository

Currently I'm using a Decentralized Shared Mainline Repository. Here's my recipe...

You will of course need a server that's accessible to everyone.

Create a group for project.

$> groupadd projectname

Create an login for each of the users who will have commit access to the shared mainline.
$> adduser --ingroup projectname username

Create a directory for the repostitory inside the web servers document root
$> mkdir /var/bzr/projectname

Set the project folders group to the project groups name
$> chown :projectname /var/bzr/projectname

Set the project folders permissions
$> chmod ug+rwx,g+s,o+rx,o-w projectname

Now you can push updates
$> bzr push bzr+ssh://hostname/var/bzr/projectname


If you need to provide anonymous access to the repository one way would be to serve it with Apache.
Alias /bzr "/var/bzr"
<Directory "/var/bzr">
Options +Indexes +MultiViews +FollowSymLinks
AllowOverride None
Order deny,allow
Allow from all
</Directory>

This would allow you to do something like this
$> bzr branch http://hostname/bzr/projectname

Jan 18, 2008

Obfuscating IDs in URLs with Rails

There are a number of valid reasons to obfuscate IDs in URLs but it's not a replacement for authentication!

My approach to this problem is to allow the database to assign a normal serial ID, which means I don't have to maintain any extra state or use special database features. Then after it's created I save the obfuscated value of the id which I can use on later lookups.

I use Knuth's integer hash because it ensures there will be no collisions and the full range of values will be used.

In this example I'm using a signed 32 bit integer for the hashed_id because it's supported by all common Rails databases. You could however adjust MAXID to any number of bits you want but then you may have to deal with storage and conversion issues.

Model:

class Part < ActiveRecord::Base
PRIME = 2654435761
MAXID = 2**31-1
def after_create
self.hashed_id = (self.id * PRIME & MAXID)
self.save
end
end

Controller:
class PartsController < ApplicationController
def show
@part = Part.find_by_hashed_id(params[:id])
end
end

Jan 4, 2008

Useful Launchpad Tips

I ran across a useful blog post today that included some useful tips for for using Launchpad that's worth sharing.