Ignored By Dinosaurs 🦕

Did Telluride last year. 'Twas a blissfully awesome return, particularly since a year earlier I thought my music career was over.

So they pick all us rockstars up at the Montrose airport. I waited around for a bit because the other dude that was getting picked up (who turned out to be Michael Daves) got in about 30 minutes after I did. He showed up and I was getting ready to walk out of the airport when somebody called my name. I turned around to see an old neighbor of mine from Boone, who I hadn't seen since. Michael Jordan. That's right. MJ was my neighbor in Boone. Anyway.

Anyway, we're riding up, shooting the shit. Daves lives in Brooklyn, I live in Jersey. So he asks me, “where you from originally?” to which I replied “Atlanta”.

“Really? I'm from Atlanta. Which part?”

“Avondale. The next town over from Decatur.”

“Yeah, I'm from Decatur.”

So then it was where'd we go to school, and I went to Boone, so we knew a bunch of the same Atlanta born Boone musicians that used to go to a pick session at the Freight Room. This was before my time as far as bluegrass was concerned. My last paycheck cashing job, incidentally, was right around the corner 10 years later at the Raging Burrito. It didn't exist then, but it was pretty cool going back to the day. He went to Decatur High, right around the corner from my parents office. I bought my first several basses at Emile Barron in Decatur. Just found this old video of Bill – the man himself.

So after about 3 minutes or so he goes,

“So if you grew up in Avondale, you must've been on the Avondale swim team.”

Hell yes I was. Swim team and the Avondale pool was the best reason to live in Avondale, as far as I was concerned. God knows most of the other kids were fucking assholes just like their parents. I digress.

“Well, we must've swam against each other then because I was on the Decatur team.”

So anyway, that was cool. The I caught his set with Thile the next day and I've been a fan since. Definitely my favorite stuff from Thile.

#music #memories #bluegrass

It's a toy I've been wanting to build for a while. I stole the domain name from Book fair and square, and have been quietly honing the skills to actually build it.

What I'd ultimately like to have is a site that is basically a collection of all current, working bluegrass bands. When you come to the front page, you get a list of bluegrass shows happening in your area. It does this by roughly guessing via your IP address. It has a list of shows in the database that it scrapes from somewhere. I used to think Facebook would come in handy for this, but it seems to have fallen somewhat out of favor as a place that bands keep updated with their shows. I tried Artist Data after that, but they have the most nebulous docs imaginable for the their API, which I'm not even sure is open.

So that's the big trick. Everything else is basically – add band, enter facebook and twitter username. It then gets bio and whatever other profile info from Facebook, whose API is somewhat open, and tweets from Twitter, whose API is way open. Yay Twitter.

It basically an experiment in modern web scraping. My first. It's built on Sinatra, for those who care. the code lives here – https://github.com/JGrubb/sinatra-facebook

Anyway, the prototype – http://sobg.johnnygrubb.com/

It's easily breakable right now.

#music #bluegrass

If you haven't seen this yet, it's a clip taken from yesterday's press event for the new Microsoft tablet. Dude launches Internet Explorer to show us around the browsing experience, but the thing immediately locks up. It's not just slow but completely frozen, and after about 20 seconds when he realizes that he's not going to be able to demo anything else he has to go swap it out for another device to get on with the presentation. Awkward!

Anyway, there's so many things that we (the royal we) want to rip on here. But I started thinking about how many times in a week I experience something similar on my iPad. I can't remember the last time it completely froze on me, but the UI isn't as snappy as it once felt.

I started thinking – is it because the touch UI is supposed to be simulating doing something tactilely – actually touching an icon and moving it with your finger – that this is so annoying? With a computer, you have this interface – the keyboard and the mouse or whatever – that still provides a mental buffer between you and the screen. If it gets unresponsive it's definitely annoying, but not anything like tapping an icon on the screen and getting the computer equivalent of “huh? what? me?”.

I know we've only started to scratch the surface (pun intended) of alternative ways of interacting with computing devices, but seriously – responsiveness of the UIs we already have has got to be a front burner issue. You really want to blow me away Apple? Make iOS 6 not turn my 3GS into an unusable brick, thereby forcing me to upgrade an otherwise perfectly good phone.

#ui

So long story short – I've been doing this thing a few years, I've learned a few tricks and it seems like every single new developer trick I learn about is already set up in the Mac for me.

I just learned about Apache Benchmark. If you don't know, Google it. It lets you ding your webserver with 100 or 100,000 requests to see how it responds under pressure. It's really cool and really simple.

Please don't do this (more than once).

ab -n 100 -c 5 http://www.johnnygrubb.com/

That means, hit my server 100 times, 5 connections at a time on the front page. Running this from the same server that the site is hosted on skips the network, which means you really are just testing the response time of the application.

This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.johnnygrubb.com (be patient).....done


Server Software:        nginx/1.2.1
Server Hostname:        www.johnnygrubb.com
Server Port:            80

Document Path:          /
Document Length:        15489 bytes

Concurrency Level:      5
Time taken for tests:   0.454 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      1623300 bytes
HTML transferred:       1548900 bytes
Requests per second:    220.29 [#/sec] (mean)
Time per request:       22.697 [ms] (mean)
Time per request:       4.539 [ms] (mean, across all concurrent requests)
Transfer rate:          3492.19 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       0
Processing:     8   21  31.5     12     209
Waiting:        8   21  31.5     12     208
Total:          8   21  31.5     12     209

Percentage of the requests served within a certain time (ms)
  50%     12
  66%     14
  75%     16
  80%     17
  90%     41
  95%     54
  98%    190
  99%    209
 100%    209 (longest request)

I'll let you decipher what all this means, but that's no caching – DB calls and page builds for every request. Nginx is barely opened up, I have one worker process up. You should see it when I turn page caching on, but I'm leaving it off for now. Running this from here at home gives me

Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking www.johnnygrubb.com (be patient).....done


Server Software:        nginx/1.2.1
Server Hostname:        www.johnnygrubb.com
Server Port:            80

Document Path:          /
Document Length:        15489 bytes

Concurrency Level:      5
Time taken for tests:   70.142 seconds
Complete requests:      100
Failed requests:        0
Write errors:           0
Total transferred:      1629080 bytes
HTML transferred:       1553936 bytes
Requests per second:    1.43 [#/sec] (mean)
Time per request:       3507.124 [ms] (mean)
Time per request:       701.425 [ms] (mean, across all concurrent requests)
Transfer rate:          22.68 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:       28 2923 1651.5   2810   12004
Processing:     0  535 658.8    320    2739
Waiting:        0    5  21.9      0     153
Total:        375 3457 1638.2   3309   12005

Percentage of the requests served within a certain time (ms)
  50%   3309
  66%   3836
  75%   3990
  80%   4326
  90%   4884
  95%   6387
  98%   9240
  99%  12005
 100%  12005 (longest request)

That's how long my internet connection takes to move 100 connections. Anyway, the point is – I had to install that on my server but only knew about it in the first place because it was already installed on this Mac laptop that I bought in 2008.

I bought this 2GB laptop 4 years ago. It was the last big thing I ever will buy with a credit card. I just put a SSD in it over the weekend, and it's gone from being almost unbearably slow to the fastest damn computer I've ever used in my life. I haven't installed anything except the tools I need to do my job. No iTunes. Not importing my mail. I need Spotify to work, so I installed that. Honestly, unless Apple's new commitment to yearly major OS updates screws me or it just melts from use, I don't see myself buying another laptop for at least another few years.

By the way, I'm sure you could melt my server if you really wanted to. Please don't.

#random

So here I go again.

I've written at length on this blog over the years about Drupal. It's a great tool for getting things done right now. It's seen a huge uptake over the last couple years among government agencies and educational institutions, so being versed in Drupal development is a good career bet at the moment, meaning over the next couple years.

In the longer term though, I see it as pretty shaky and here's why.

Drupal's raison d'etre is that non-technical users (meaning – people who aren't programmers) can build fairly complex sites without writing a lick of code. It has seen massive growth, mainly because the fact that websites are actually computer applications with which users interact is a fact that is really just dawning on the majority of people who use the internet and/or need a website for their business. Most people don't have CS degrees, but every business needs a website. Thus, they either turn to someone who knows how to build websites, or they hook up with GoDaddy and do a one-click install of Wordpress.

However...

I think the world at large is rapidly getting used to the idea of writing code, and the proportion of people out there who are at least somewhat comfortable enough with that idea to hack together their idea is growing. And their idea might not be a good candidate for a Drupal site. The other thing about Drupal is that whatever your idea is, you can probably get pretty close without writing code, but chances are high that it's not going to be exactly what you want without writing some code (or hiring someone to write some code). And at that point, you either settle for something that isn't what you want or you teach yourself to write some code. And after you get comfortable with writing code, you start to wonder why you are dealing with all of this Drupal overhead that you didn't ask for in the first place. And some time after that you might find a language like Ruby, that makes infinite more sense to me than PHP, and looks a hell of a lot prettier to boot. And soon after that you might find it hard to get excited about Drupal work, because overriding other people's code is way less fun than writing your own to begin with, and that's the vast majority of working with Drupal code, at least form the backend.

updated Jan 2014 for Rails 4, see bottom


I just got this blog up and running yesterday, a marathon of pain but ultimately successful. So today I wanted to add some Markdown action so I didn't have to drop into TextMate to add <p> tags to everything all the time.

RedCarpet seemed to be the gem that was recommended, but it's recently seen a complete API overhaul that has rendered useless the vast majority of the de facto documentation out there. So, viewers of the Markdown Railscast, this one's for you.

It only involves a few changes, so if you're here it's likely that you know how to install it and you're here because of that “no 'new' method” error. Instead of

<%= Redcarpet.new(@post.body).to_html %>

as mentioned in the Railscast, you'll need to do a little more setting up. This is how I did it.

# app/helpers/application_helper.rb

def dat_markdown(text)
 markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML,
 :autolink => true, :space_after_headers => true, :no_intra_emphasis => true)
 markdown.render(text).html_safe
end

The first parameter is which renderer you want to use (either HTML or XHTML, for what?), and everything after that is your options glob which you can get from here. For readability you could also do -

# app/helpers/application_helper.rb

def dat_markdown(text)
 options = {
 :autolink => true,
 :space_after_headers => true,
 :no_intra_emphasis => true
 }
 markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, options)
 markdown.render(text).html_safe
end

After that all you have to do is

<%= dat_markdown(@post.body) %>

and you're on your merry way. Enjoy.

January 2014 update

Rails 4 – check out Kramdown. This is how easy it is now.

# application_helper.rb

 def markdown_filter(text)
 Kramdown::Document.new(text).to_html.html_safe
 end

and <%= markdown_filter @post.body %>

Super bonus for the demographic reading this – syntax highlighting is included for free. See above. Docs for the options hash are here.

#rails

My first post on my new blog! I wrote this one all by myself, with the help of hundreds and hundreds of open source collaborators, Stack Overflow commenters, IRC, Google Groups, and sheer force of WILL!!!

This is my first running, production Ruby on Rails app. It took me about two days/6 hours to write, and about 4 days/30 hours to deploy. Deploy means “make work on the web so people can see it” and it was every bit the pain in the ass that I'd heard it was supposed to be. But by god, here it is! Nginx/Passenger/MySql/Rails. I'll make it look prettier later, and hopefully also have something to say.

Guess I also need to set it to something other than Greenwich mean time. It begins! Some more!

#rails #random

I was listening to RadioLab the other evening during the WNYC pledge drive. During the part of the show in which they were actually driving pledges they announced one of those perks for donors of a certain level, I think they called them “lab partners”. It entitles you to some stuff, some interactivity with RadioLab producers, and the obligatory “exclusive content”. The very first thing that popped in my head was -

I'm tired of content

I got to thinking. Commerce and economics. Supply and demand. Scarcity.

Take music – music was once a thing that could only be experienced live. The recording era ended all of that and ushered in a successful business model that had a good run of 80 years or so by not only increasing the supply of music to people, but by exponentially increasing the demand. Previously if you wanted to hear Beethoven's music you needed to go to the symphony to hear it, but now you could put on a record and listen to it. Not only that, but after the performance had ended you could put on some Pink Floyd, and after that whatever else. You weren't confined to listening to music once a day (or once a month), you could basically listen to it all the time.

But, the commerce of the business was still driven by scarcity since after all, you still needed a record and a record player. You still had to go down to the store to buy the record, if it was even available yet. Records could be released on a date, remember that? Now what?

Records are routinely leaked on the internet and unlike a physical resource that leaks out of something, the instant something digital “leaks” onto the internet the supply will forevermore outweigh demand. How do you build a business around that?

I've been pondering this for as long as anyone and I now think that “exclusive content” completely misses the point. I don't give a rip about exclusive content because there's no such thing. Trying to create this impression of scarcity to stoke demand is pointless because there's an endless wealth of other content that's free right now. Don't even demean your customers or fans with it, because it only means that they will have to jump through a hoop to engage with it. Everybody else will be casually engaging with the free stuff at their convenience. If you're lucky.

If you're lucky you will have patrons, not customers. Customers barely exist in the creative world now.

#random #business

I'm reading this morning and I come across a post about a thing that somebody wrote called (or subtitled, I'm not sure) Node.php. Anyone who doesn't understand what it is by looking at the name wouldn't understand my explanation for what it does, so whatever.

For the non-programmers —

It's written in a language called PHP. PHP, despite being the backbone for the server side component of a huge number of the largest websites in existence (as well as this tiny little one), is almost universally derided in hacker circles. It's sort of like the Alvarez guitar of programming languages. No “real professional” guitar player would be caught dead playing anything but a Les Paul or a Strat, so the Alvarez is widely acknowledged to be a “starter” guitar, much like PHP is “starter” language to some people.

The problem is that this is all a bunch of pseudo-religious hokey, and (many) hackers are more vain, egotistical, and prone to engaging in flame wars over their chosen tools than even musicians. Any actual real professional musician knows good and damn well that he can get a beautiful sound out of an Alvarez and that only rookies have the time to make fun of each other for their choice because the pros are too busy creating.

I typically play a plywood Chinese bass that's been cut up into little pieces and I get a damn good sound out of it. Is the sound better than my carved bass? Is it easier to play? No. Does that stop me from rocking the joint with it? No.

So why in the face of so much evidence that PHP is a perfectly useful language to a vast number of programmers of all skill levels around the world does it garner such derision? Someone please explain it to me as if you were trying to convince a non-programmer that they should care because the whole thing seems a little immature.

#technology #php

So I've decided to start playing around with CodeIgniter. It's a supremely simple PHP framework that has a lot of good documentation, a pretty big user/developer base, and has a lot in common stylistically with Rails. I've just really started playing around with it, and wanted to use the migrations feature for building up my database. I won't explain what migrations are or how they work or why to use them because that's been covered.

Our project will be something like a database of shows. So we need a “shows” table in our database. CI needs you to edit application/config/migrations.php to change $config['migration_enabled'] = FALSE; to $config['migration_enabled'] = TRUE;. This will enable migrations in the app. The next meaningful line down the page – $config['migration_version'] = X; will tell your app which migration it's supposed to be on. If you're working with someone else and they update their codebase from a repo, then their app will check their local development database, see that X number of migrations have not been applied (by checking the version number in the migrations table in the DB) and bring the schema up to date. It's neat.

Step 2 will be to write our first migration. Under application/ you'll need a /migrations directory (application/migrations). This is where you'll write out the migration file. About here is where you start realizing some of the amazing things that Rails does for you, such as building all of this with a line on the terminal instead of making you trot all over you app to set this up. I digress.

Our first migration will look like this -

// application/migrations/001_add_shows.php
 
php defined("BASEPATH") or exit("No direct script access allowed");

 class Migration_Add_shows extends CI_Migration {
 
 public function up() {
 $this-dbforge->add_field('id');
 $this->dbforge->add_field(array(
 'date' => array(
 'type' => 'DATE',
 'null' => FALSE,
 ),
 'location' => array(
 'type' => 'VARCHAR',
 'constraint' => '255',
 'null' => FALSE,
 ),
 'description' => array(
 'type' => 'TEXT',
 'null' => TRUE,
 ),
 ));
 $this->dbforge->create_table('shows');
 }

 public function down() {
 $this->dbforge->drop_table('shows');
 }

 }
?>

So here's what this says -

We're creating a migration called “Add shows”. This will create our “shows” table in the DB. It will have an 'id' column. By using $this->dbforge->add_field('id');, CI knows to make this your primary key, to make it an auto-incrementing integer, and for it not to be NULL (http://codeigniter.com/userguide/database/forge.html#addfield). We're also adding a date field, a location field, and a text description.

The name of this file is important. If you call the class Migration_Add_shows and name the file 001addshow.php (singular), CI won't be able to find it. This is it for step 2.

Note: the down() method is for reversing this change. I haven't figured out how that works just yet from the standpoint of running the down() migration, but you'll want to write the reverse of any up() method for every migration. This is the “undo” button on this process. Ignore it at your peril.

Step 3 is to create a migrations controller, since you'll need this migration to be called from somewhere. I will learn how to run migrations from the command line next, since the CLI is obviously where it's at, but for now we'll write a controller and do it the hard way.

// application/controllers/migrate.php
 
php defined("BASEPATH") or exit("No direct script access allowed");

 class Migrate extends CI_Controller {
 public function index() {
 if (ENVIRONMENT == 'development') {
 $this-load->library('migration');
 if ( ! $this->migration->current()) {
 show_error($this->migration->error_string());
 } else {
 echo "success";
 }
 } else {
 echo "go away";
 }
 }
 }
?>

Now, if you visit yourapp.com/index.php/migrate, you'll have run the migration. It took me a few minutes to get this wired up correctly, and CI gives you some useful error messages, so hopefully you'll be on your way. Basically this says -

This can only be run while in development mode, else “go away” and stop monkeying with my app. Load the migration library, which runs the migration up to the version specified in config/migrations.php. When you add a new migration, update the version number in that file, and it'll be run next time you visit this url.

Did you get all that?

#php