Tuesday, October 30, 2007

Leopard Replaced Things

Leopard, you sexy cat, blah blah blah. I won't bore anyone with my usual cheekiness, due significantly to the fact that I'm doped up on Skelaxin tonight. Relaxation: it feels good, but makes you boring as shit.

So, on to the show.

There are a million OSX 1.5 reviews out there, but rather than talk about all of the new cool features that I'd like to bone, let me briefly mention five programs I was able to uninstall due to Leopard improvements.

  1. Terminator replaced by Terminal. Like many others, I was annoyed at the old Terminal's lack of tab support. The new Terminal has not only matched Terminator, with things like tabs and process exit safety, but succeeded it with Window Groups to configure terminals in bulk. Cool.

  2. SuperDuper replaced by Time Machine. To be honest, SuperDuper is actually slightly fuller featured, with scripting support; but I never used it anyway. Time Machine is automatic, free, and almost more difficult not to use.

  3. You Control Desktops replaced by Spaces. It's been a full day and Spaces hasn't crashed yet - so it's already one better in my book. I also enjoy the "only launch here" feature of Spaces - so you can bind a specific program, such as Firefox, to a specific desktop, such as #4. No more manually managing where my windows live.

  4. NetNewsWire replaced by Mail. Simple, elegant, one program, and opens links into your default system browser, ironically, not just Safari.

  5. Finally, Candy Bar was removed because the current icons don't look like they belong in Candy Land. They are simple and bold - just like me.

I'm still no Mac fanboy, but I can feel it creeping on. A few more releases like this, and I may never have to install anything at all. It's like I always used to say about Windows - it's great - as long as you don't have to install anything on it. It was a joke, but I almost wish it with Mac. If Apple and Google could only spawn a bastard company, I'd gladly let it run my life.

Run, It's a OSX1.5!

A Leopard... get it?

Well, I'm installing it today. In about 5 minutes to be exact. If I don't post for a few days, my laptop has exploded in my face. But if all goes well, I'll be back in an hour or two.

Start the stopwatch... now.

Monday, October 29, 2007

Apply Directly to the Forehead

SnipSnipe is now sexy.

If ever I'm wont to condescend over look-and-feel as substandard to substance, I apologize. Sure, you can declare the importance of your fugly girlfriend's sparkling personality - but who cares if I'm out dating supermodels? That might sound mean - and it probably is - but I've spent the better part of my open-source life working on ugly projects with awesome guts, whilst my friends toy with the inverse.

No more.

I want a project with more than geek cred. I want to point at something hot and say, "yo, check it," ghetto-fab and all. I want the money shot, which leads us to an analysis of this post's title. Apply Directly to the Forehead. A simple commercial with a catchy hook. Nothing special about this product, really, yet it sells millions. Why? Because it gets in your brain, like an African zombie infection. Before you fall in love, you have to love the look of the person you are with (unless you are betrothed or desperate) - else why else would you start talking? Initial attraction is important. Sure, we all need more than bread and circuses, and anyone with an I.Q. larger than their shoe size desires more than style, but style cannot be ignored. Style is more than a popularity contest. In the right hands, style gives you the attention required to cultivate substance. This is a lesson Maven and Java are only recently bothering to learn.

Consider RAM.

The first non-PC computer I ever bought was a Sun Ultra 5 SPARC. Sure, I was the envy of my friends, and naturally chicks dug me like a busted water main, but it had a slight drawback - parity RAM was fucking expensive. Sure, it was more reliable, but it was also $400 for 128M. Compare this to the $40 for your standard PC SDRAM at the time. A few years later, Sun dropped their superior parity RAM to the much cheaper PC-style RAM. Why? PC had market-share, which allowed their costs to drop, which meant Sun could no longer compete by manufacturing their high-end RAM for workstations. Since PC RAM had the money, they slowly improved.

Improvement follows the user base. A similar thing happened with video cards driven by the video-game market; it hardly mattered that the scientific visualization hardware was better. Soon the pure amount of cash pushed into video-game cards eclipsed pricey and fancy architecture.

The point I make here is not dissimilar to statements about using Rails over Java for most web projects... the requirements for a clean architecture often pales in comparison to something marginally as good, but much cheaper. Similarly, there is value in making software more usable at the behest of Ivory Tower elegance. A few years ago an IIT created a P time prime-number generator - but it hardly mattered since years earlier hackers created much more efficient algorithms, though not as theoretically clean.

Back to SnipSnipe. I spent the past week putting a pretty-face onto the site, though it works no differently. Some have told me it was a waste of time, but I disagree. If users are not immediately attracted to it, they won't use it - despite the slight quirks. And if people use it, I can rationalize spending more time to fix it. Call it Adoption-Driven Development.

  1. Make your project work in a basic sense.

  2. Give it an attractive look and feel.

  3. Improve workflow.

  4. Add extras and tools to make it a seamless experience.

  5. Refactor the code to elegance to deal with increased user load.

This may seem backward from common wisdom (which as everyone knows, is hardly common and only occasionally wise) which dictates workflow, then elegant architecture, then make it pretty at the end. Hell - on any other day I may even advocate it - but not today. Today I endorse the above list, like so:

The first steps make your product basically useful, something someone wants to use. Then something those early adopters want to continue using. Then feedback to incrementally improve. Only then worry about elegant architecture. As I have said time and again: most project fail anyway - this is a great method of development to see as early as possible, putting in the least amount of work, if your idea is worth putting in the long hours.

Don't worry about the geek-cred at first, make your application love at first site to your users. Win the sip test, then worry about the chug test. Don't worry about engaging the brain to start, begin by applying directly to the forehead.

Wednesday, October 24, 2007

Code Te Ching - Verse 38

The highest understanding does not show it,
    therefore understands.
The lowest understanding is always aware of it,
    therefore does not understand.

The highest understanding does not force action,
    And does not need to.
The lowest understanding forces action,
    Because it needs to.

The highest merit takes action,
    But need not act.
The highest certification takes action,
    And it must act.
The lame takes action,
    And when no one responds to it,
    It rolls up its sleeves and screams.

Thus it was:
    When the Code is lost,
        Understanding appeared.
    When understanding is lost,
        Merit appeared.
    When merit is lost,
        Certification appeared.
    When certification is lost,
        Lameness appeared.

Lameness only projects good intention and sincerity,
And is the beginning of disorder.
Swift learning is only a flower of the Code,
And the beginning of stupidity.

Therefore the elite dwells:
In the thick, not the thin.
In the fruit, not the flower.
Rejects one, accepts the other.

Tuesday, October 23, 2007

Snip Snipe Code-Tagging Plugin

I've taken my first crack at a Firefox extension for SnipSnipe out at the Mozilla extensions developers sandbox. Take a look, it's easy to use! (Although I'd appreciate anyone with FF sandbox access to download via that channel, you can also download the plugin directly from here)

After installing the plugin and creating a user account on snipsnipe, find some code you like and highlight it. Right-click and select "Share Snippet..."
This will open up a new tab pre-populated with the snippet and the URL where it was found.
Just give the snippet a title, short description and some tags (don't forget the programming language... that's how snipsnipe knows how to highlight the code).
Submit the new snippet and that's it! Add all the snippets you want... it's free :)

Sunday, October 21, 2007

Code Te Ching Book I - Code

What is the sound of one hand hacking?

Book I (道) of the Code Te Ching is complete. Following the style of four standard English translations of the Tao Te Ching (道德經), and the two texts from Ma Wang Tui (馬王堆帛書), A (chia) and B (i) compared by Prof. Robert Henricks.

The central concept of the TTC is its preaching of wu wei (non-action), or action without high-minded ideals, action that does not have a conceptual driving force, or action done for the act - not the fruits of the act. We can only assume that the author(s) created these verses as a labor of love, not out of a desire for some future reward or high-minded ideal. There are those who say that action not driven by rational thought is blind and that its results are substandard. The realizations within the Taoist texts, like the Tao itself, could not have been the same were they analyzed or pinned down with any rigid western conceptual framework. This potently short, 5,000 character, 81-chapter book has endured for eons. If nothing else: that is proof positive that action does not have to be intentional to be good or lasting.

This relates to my philosophy of code. Simplicity, subtlety - these are the ways of the master. Thus spake Jeff Hawkins:

Complexity is a symptom of confusion, not a cause.

Simplify a problem, framed in its most basic essence, and no coding problems are insurmountable. There are many ways to simplify, thinking down to the machine, or up to the highest levels of abstraction... somewhere there exists an answer. Getting stuck in a silo stifles thoughts and breeds substandard results. Sometimes you must think like a customer, or a client - a coder or a manager - but always effortlessness is the goal. This is the way of the master, the hacker, the elite. Simplicity is the way, agility is the method.

Book II is next, and focuses on team leaders: Te (aptly pronounced "duh").

Tuesday, October 16, 2007

Cheap Tricks X - Managing Ruby Gems from MediaWiki

In Cheap Tricks III I relayed a little script I wrote to keep everyone at work in sync concerning groups of ruby gems. As the number of projects expanded I was forced to also expand the way we managed that list - other than passing it around or requiring everyone to svn update. Thanks to a little-known MediaWiki action, we are able to keep a list in the wiki.
require 'net/http'
require 'yaml'

def gem_install(gem, version, url=nil)
# only install if not already installed
listed = `gem list #{gem} --no-details --local`
unless listed =~ %r"^#{gem} "
puts "== Installing #{gem}"
puts `sudo gem install #{gem} -f -y -v '#{version}'`
end
end

# First try and find a local or given gems.yml file
gems_config_file = ARGV[0].nil? ? 'gems.yml' : ARGV[0]
gems = nil
begin
gems = YAML::load_file( gems_config_file )
rescue Errno::ENOENT => e
puts "Could not find file... looking remotely in the wiki Gems.yml"

url = URI.parse('http://wikiserver/')
res = Net::HTTP.start(url.host, url.port) do |http|
http.get("/index.php?action=raw&title=Gems.yml")
end
data = res.body
gems = YAML::load(data)
end
gems['gems'].each { |gem| gem_install(gem[0], gem[1]) }
If the gems.yml cannot be found locally and is not passed in as an argument, then the script will grab the YAML file from the wiki, in an article entitled Gems.yml. The yml file has the same structure as any other YAML file... it just lives in the wiki. Notice in the URL I have "action=raw". This is a MediaWiki command to return the raw article data, not rendered. If you don't have MW, you can equally put this into something like Subversion and grab it that way. Whatever.

As an added bonus, I updated the gem_install method to skip gems that were previously installed.

Happy "Cheap Tricks" #10 Day! Huzzah!

Monday, October 15, 2007

Back to Work

I've been gone for the past few days in Key West for a retreat. Standard coding shenanigans will ensue when my hangover wanes. We floated into the airport like bloated, beached whales - and there I decided that if you smile at the end of a vacation, you did not have enough fun. No, the face of true fun is grim, bloodshot and reeks of stale margarita. Jocularity takes effort - and an ounce of residual effort is an ounce of vacation squandered.

True relaxation is complete and total burnout.

Once I replace my wick and get my pilot light lit, I'll spit out (up?) more... stuff.

In the mean time... who are those handsome devils?

Wednesday, October 10, 2007

Sustainable, Sushmainable

Here's the thing: "A Standish Group research report shows a staggering 31.1% of projects will be canceled before they ever get completed. Further results indicate 52.7% of projects will cost 189% of their original estimates... On the success side, the average is only 16.2% for software projects that are completed on time and on budget. In the larger companies, the news is even worse: only 9% of their projects come in on time and on budget."

Well, don't freak out - or nod in knowing agreement for that matter. This report is over a decade old (The CHAOS Report). So, times have changed, right? A 2004 update shows that project cancellation has actually declined to 18%, and project success has risen to 28%, supposedly.

Big flippin' deal.

No matter what side of the fence you side on, can we at least agree that - oh, say - only 50% of software projects actually succeed? In other words, any given project you are on is really a coin-flip on whether it will ever be used.

This leads to my argument: I hate Java and .NET - bloated, confusing framework garbage. I've ranted about Java-esque static-typed OO languages before, and still point a cold boney finger at them as the culprit. Despite any philosophical musings, the above facts are the real reason I now stick mainly to agile languages. The numero uno reason I hear in favor of Java and .NET? "They are sustainable." Again:

Big flippin' deal.

I cannot stress enough how important it is to just get software out the door. Sustainability? Puhleeze - your project, if it does survive, won't last 10 years. Scalability? Don't kid yourself - your Killer App will likely never get that popular. I got SnipSnipe (check it out) done in Rails in a week. If it were Java, I'd still be working on it. Sure, I am still working on it, but that doesn't mean you can't use it.
$ rails snipsnipe; cd snipsnipe
$ mysqladmin create snipsnipe_development
$ script/plugin install http://svn.techno-weenie.net/projects/plugins/acts_as_authenticated
$ script/plugin install http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids
$ script/plugin install http://juixe.com/svn/acts_as_commentable
$ script/plugin install http://juixe.com/svn/acts_as_voteable
$ script/generate model Snippet
$ script/generate authenticated user account
Make a few migrations and db:migrate, hang the acts_as_* gang onto the Snippet model.
class Snippet < ActiveRecord::Base
acts_as_taggable
acts_as_voteable
acts_as_commentable

belongs_to :user

validates_presence_of :title, :body_raw
validates_format_of :credit_url,
:with => /^http(s|):\/\/|^$/,
:message=> "must begin with http://"
end

There. That's the framework of SnipSnipe. The rest was just html/javascript and about 80 lines of controller code. Most of my time spent was fighting with Prototype and CSS. But, back to the task at hand.

Forget that fact that your project has only a 50% likelyhood of ever getting used at all, what are the odds of sustainability or scalability ever becoming a problem? If you ever write software that gets to these next levels - then, and only then, should you worry about such navel-gazing. In the interim, you can work on more new projects. Yay! Until then the best advice I can give is, just get the bitch out the door! (You can quote me on that)

Tuesday, October 9, 2007

Warning: Terrible Things are Said

Fuck Joyant, Fuck TextDrive. I signed up for TextDrive in mid 2004, one of the first customers to do - largely because they were the only Rails host in town. They were awesome. Great staff, responsive, and never oversold their capacity - for less than $100/yr you got the best hosting around - hands down.

Sometime around 2005 they were purchased by Joyant, and the clusterfucks ensued. Check out Meopedia - a simple (very simple) MediaWiki instance, without too much traffic. It's slow as balls. For 6 months the Joyant staff has claimed "we're upgrading our servers, please be patient". I have a pair simultaneous possible replies in my head, equally valid, waiting to materialize - Schroedinger's Replies, if you will.
  1. If your servers are taxed, why are you still selling space? TextDrive never did before - if they didn't have the servers, they didn't allow new customers.

  2. Fuck off - I'm paying for a service. I'm glad you're growing (not really) but that's not my problem. Now give me the service I paid for, or give me my money back.
This alone is hardly worth my ire. Their quality has been slipping glacially. What really got my goat was that I recently lost the password to an account (the one I was to launch SnipSnipe onto). I filed a support ticket (at top priority) to reset my password.

A week later, I finally got a response.

Were this something not so routine I'd not be bothered. Were it not the case that I was in a hurry to launch SnipSnipe ASAP, I'd not be annoyed. Were it not the fact that their servers run increasingly slower for increasing prices, I'd not be pissed. It's the combination of these things that make me angry enough to blow another wad of cash on a new host. Let's face it, I've stuck with TextDrive for 3 years during their slow, painful fall - I'm not exactly hard to please. I just hope RailsHost works better.

In other news - if you hadn't noticed - SnipSnipe is on (remember, activate your account BEFORE adding snippets)!

Friday, October 5, 2007

Code Te Ching - Verse 37

The Code endures with no name.
Were process able to posess it
the machine would work on its own.

Were this the case
our lives would become simplicity.
No more disgraceful meetings

Also: no paychecks

-- The Code

Thursday, October 4, 2007

Framework Heroes - Ruby on Rails

Today I flirt with disaster - like some sort of hooker, looking to give disaster a good time. This is possibly disastrous because, I fear, I may lack the fortitude to stop. Yet, about to bed down for the night I birthed an epiphany: what kind of heroes would different web technologies be, if they were anthropomorphic comic representations of their inner nature?

Today, I debuted with Ruby on Rails, because well, it's ttly my fav lol!!!11one However, as much as I like it, it is largely untested for huge systems with high traffic. Until I see it running with the big boys like a Google or Amazon, it'll not be taken seriously enough... but you still gotta love the little scamp for trying.

Wednesday, October 3, 2007

5 Minute Ajax Voting in Rails

I (heart) Ruby and I like Rails. I don't love Rails, mind you, but some days I like it more than others. Today, I like it very much. Mostly because it was trivial to add nice Ajax-y voting behavior to my model with relatively little work. How little? It took less time to actually do, than it took me to write about it here.

So, here's how it's done: Install acts_as_voteable plugin as directed on Juixe. Sticking with their nomenclature, I will assume the active record you wish to treat as voteable is Post.
class Post < ActiveRecord::Base
acts_as_voteable
end
Quick Note: don't forget to add
<%= javascript_include_tag :defaults %>
to your html head, else you won't get all this delicious Ajaxiness.

Create a partial file called _vote.rhtml. This contains the snippet of code that actually generates the voting interface, as well as what is displayed to the user when it's updated.
<span id="votes<%= voteable.id %>">
<%= link_to_remote "+(#{voteable.votes_for})",
:update=>"vote",
:url => { :action=>"vote",
:id=>voteable.id,
:vote=>"for"} %>
/
<%= link_to_remote "-(#{voteable.votes_against})",
:update=>"vote",
:url => { :action=>"vote",
:id=>voteable.id,
:vote=>"against"} %>
</span>
Notice that we are suffixing the span's ID with the voteable object's ID. This is so you can render the _vote partial multiple times on a page, creating a unique block for each voteable object (for example, multiple Posts per page). The object is also named "voteable" and not "post" - this is because there is nothing about this file that is specific to Post, any object that acts_as_voteable can be passed into it.

When the above code renders, it will look like the following: +(5) / -(6) (yet, functional)

Next, create a file named vote.rjs that contains the Ajaxy goodness that dictates what to replace the span ID of "votesID". What does it replace it with? The exact same partial we just created. Only this time, the re-rendered version will have an updated vote-count.
page.replace("votes#{@post.id}", :partial=>"vote", :locals=>{:voteable=>@post})
To use the above code, just render the partial into your view (whatever it's call, for example, view_post.rhtml). Render the above partial and pass in the voteable object, as shown:
<%= render(:partial=>"vote", :locals=>{:voteable=>@post}) %>
That's all for the view layer - just two new files and adding a line of code to your existing view. Finally, to make the code work, add the vote action to your controller:
def vote
@post = Post.find(params[:id])
@vote = Vote.new(:vote => params[:vote] == "for")
@post.votes << @vote
end
This technically works. However, if you launch this, there will be no way to stop someone from clicking the link as desired, to get the score they want. The following extension will only allow logged-in users to vote, and then only once (made to work with acts_as_authenticated).
# One man, one vote
def vote
return unless logged_in?
@post = Post.find(params[:id])
unless @post.voted_by_user?(current_user)
@vote = Vote.new(:vote => params[:vote] == "for")
@vote.user_id = current_user.id
@post.votes << @vote
end
end
Note that I do not set @vote.user = current_user, this is to bypass an intermittent type error - I don't precisely know why it occurs, but is likely due to session object marshaling or gnomes. This is how I got SnipSnipe voting to work. More on its architecture after launch, stay tuned.

Tuesday, October 2, 2007

Code Te Ching - Verse 36


Language is only convenience.
Do not confuse it be more.

Language allows for a path to understanding,
    this is true, but
Language can chain the strong to non-understanding -
    there is no "right" way to code (in all cases),
    and no "right" language to use (in all cases).

The elite knows the simple truth:
    speak the correct language
    at the correct time

Monday, October 1, 2007

New Domain, Et Cetera

In the normal daily course of actions, I tend to hold fast to my belief in (with an inverse 'sup'-style nod to Terry Pratchett) a Very Strong Misanthropic Principle: The purpose of the universe's existence is to harass me, evinced by the fact that I'm always getting screwed. However, there are occasions for delight, where my karmic accounts payable has yet to balance, giving my life the illusion of being in the black. It is for these moments that I remain a silly optimist, despite all contrary evidence. One of those moments is today.

Good thing #1: This blog now has a real domain @ http://www.coderoshi.com. You can still hit it at blogspot, but now it just looks cooler.

Good thing #2: The blog has it's own ico. Which is good, because I wanted something other than that little orange "B".

Good thing #3: I finally got my tagging system working, save for one small hiccup. On what, you ask? Stay tuned... my new gift to the open source community will launch soon (hopefully later this week). In permanent beta, of course :)

Finally, I'm looking forward to a nice little financial windfall, taking a trip to the Floridian Keys in two weeks, and a new episode of Heroes plays tonight.

Yes, life is good...