Working at Recurly is awesome
To celebrate an internal product launch, we took a half-day off and drove up to Tiburon for a long lunch and then rode the ferry back to the city. An awesome day with great people.
Want to come work with me? We're hiring.
Deana's got a blog
While I knew that Deana had started a blog about being a mom in Berkeley that she's been working on for a while but—until she asked me to check that video was showing up on it today—I didn't realize how much she'd been working on it. But now that I know she mentions me on there I added it to my feed reader so I can keep up-to-date.
RMO does Double Bunny
Last year when the Rude Mechanical Orchestra was recording our second album, Too Big To Fail, I shot some video. I finally got it all edited with the recording from the album. If you like it you can listen to or download the full album on the band's website.
Got married, moved west
Posting that last video made me realize I've been really bad about keeping up on this whole blog thing. I hadn't said anything about getting married to Deana back in August, or packing up and leaving New York, the month we spent in Reno while I found a job and apartment here in Berkeley. Well, that all happened and at some point it'll end up in a video.
We found a really nice apartment right the middle of Downtown Berkeley, I got a great new job at a startup in SF called Recurly and we've seen a lot more of my side of family. It's strange how different Berkeley is from Brooklyn: there's no trash or graffiti, 50°F is considered cold, you can always smell someone walking down the street smoking weed. Some of the grimier things were what gave Brooklyn a real texture and flavor. I haven't quite figured out Berkeley's flavor but I really do love having a board game store right around the corner for those nights I need to run out for a copy of Carcassonne.
Rafting on the Hackensack River
Finished another video a couple weeks back and forgot to post it here. I've been trying to go through a lot of the footage I shot while I was in NYC and turn it into projects. I've got a few more in the queue that I hope to get out over the next month. I hope you like it.
As a developer I belive
I've been doing some work on my resume and my summary kept starting to sound like a manifesto. I decided it was better to just simplify the resume and turn this into a blog post.
Technology doesn't exist exist in a vacuum
People create it and use it. Taking time to understand the motivations and needs of clients and users lead to more informed decisions and ultimately make a project more successful.
The team owns the code
It should all follow a common coding standard. You shouldn't be able to tell Eric was editing this section because he left it littered with tabs, while everyone else uses spaces. It also means it's important for members of the team to review each other's code and give feedback. It's also important for people to listen to that feedback. Code review provides a good way to share knowledge: "oh, that trailing comma in your array will cause IE to blow up." Even if the review just points out a typo in a comment, it sets the expectation that other people will be reading and trying to understand your code.
Code needs to explain itself
If you're doing something that looks squirrely you need to say why so the next developer doesn't come along and "fix" your code. If you're putting in a quick hack to close a ticket, say so! Spend a few minutes to list the pros and cons that lead you to this solution so that when you're staring at the code a year from now you don't have to rediscover them.
Documentation is important
If people can't figure out how to use or maintain your product then it's not finished. The documentation also needs to be close at hand. This ties back to code needing to explain itself but also extends to UI, make the ramifications of a choice apparent.
It's worth spending the time to do something right the first time
Of course there are times when you need to just get it done and launch, but as layers of code accrete on top of it, you'll only find it harder to come back fix something.
You should play devil's advocate
I'm happy to take the other side and argue against each of these points.
I made a video
I finally finished this video about our honeymoon in California. I'm really happy with how it turned out, it's definitely the best thing I've shot and edited to date.
Better New Relic reporting on sites with Panels
My last week at DoSomething I spent some time working on getting better metrics on which panel pages are slow. One half of that was to use New Relic's PHP API to provide better transaction names that included the node type and panel name:
<?php
/**
* Implements hook_page_alter().
*
* We want to provide more detail to New Relic on the transaction and late in
* the page build seemed like the simplest place.
*/
function example_page_alter(&$page) {
if (!extension_loaded('newrelic')) {
return;
}
$name = NULL;
// Look for a panel page...
$panel_page = page_manager_get_current_page();
if (isset($panel_page['name'])) {
// If it's a node page put the argument's node type into the transaction
// name.
if ($panel_page['name'] == 'node_view') {
if (isset($panel_page['contexts']['argument_entity_id:node_1']->data)) {
$node = $panel_page['contexts']['argument_entity_id:node_1']->data;
$name = 'page_manager_node_view_page/' . $node->type;
}
}
// If it's a page_manager page use the panel name.
else if ($panel_page['task']['task type'] == 'page') {
$name = 'page_manager_page_execute/' . $panel_page['name'];
}
}
else {
$menu_item = menu_get_item();
if ($menu_item['path'] == 'node/%') {
// Looks like panels didn't have a variant and it's falling back to
// node_page_view.
$name = 'node_page_view/' . $menu_item['page_arguments'][0]->type;
}
}
if ($name) {
newrelic_name_transaction($name);
}
}
?>So once you know which panels are slowing down your site you can use the new Panels, Why so slow? module to put the blame on the specific panes.
Report a deployment to New Relic (in python)
I wanted to be able to have a fabric script report a code deployment to New Relic and eventually after brushing up on my python worked this snippet out:
import urllib
import urllib2
try:
request = urllib2.Request(
'https://rpm.newrelic.com/deployments.xml',
urllib.urlencode({'deployment[application_id]': 'YOUR APPLICATION ID'}),
{'X-api-key': 'YOUR API KEY'}
)
response = urllib2.urlopen(request)
except urllib2.HTTPError, e:
print 'Error reporting: ', e.code
print e.headers
print e.fp.read()Publishing pecl channels to GitHub
The process I used to build: http://drewish.github.com/phpredis/ to address this issue: https://github.com/nicolasff/phpredis/issues/42
Install prium:
pear channel-discover pear.pirum-project.org
pear install pirum/PirumCreate a pages repo. I did this as a separate checkout in a sibling directory:
git clone git@github.com:drewish/phpredis.git phpredis-channel
cd phpredis-channel
git checkout --orphan gh-pages
git rm -rf .Configure the pirum.xml file then build the channel:
pirum build .Add your channel to pear/pecl (this also validates it and warns you of any
problems before you push it up to github):
pecl channel-add channel.xml If that looks good then add all files and push it:
git add -A
git commit -m "Created the channel."
git push origin gh-pagesHop up a directory (since I've got them as siblings):
cd ..Package up a release:
pecl package phpredis/package.xmlSwitch into the pages repo:
cd phpredis-channelAdd the release to the channel:
pirum add . PhpRedis-2.2.1.tgzIf that doesn't have any errors then commit the changes and push them:
git add -A
git commit -m "Adding the PhpRedis-2.2.1 release."
git push origin gh-pagesSources
http://blog.stuartherbert.com/php/2011/09/22/php-components-publishing-y...
http://blog.shupp.org/2010/12/24/github-pages-pirum-easy-pear-channel/
https://help.github.com/articles/creating-project-pages-manually
Drupal on Mountain Lion (OS X 10.8)
The instructions still need some work. I'd did some updating but haven't tried using it with a clean install yet. After reading this it sounds like there's some bigger changes. I've also been trying to switch from macports to homebrew so that'll also mean some changes to this.
Install XCode
Install XCode from the App Store. Run Xcode and open its Preferences (⌘+,) select the Downloads tab and then the Components sub-tab. Click the Install button on the Command Line Tools component.
Install MacPorts
Follow the directions to install Mac Ports.
Become root
To follow these instructions you need to be running as the root user using the default sh shell. If you've got administrator permissions you can open up a Terminal window and switch users using the sudo command then provide your password.
amorton@minivac:~% sudo su
Password:
sh-3.2# Install MySQL
Use port to install MySQL:
/opt/local/bin/port install mysql55-serverYou'll need to create the databases:
sudo -u _mysql /opt/local/lib/mysql55/bin/mysql_install_dbLet launchd know it should start MySQL at startup.
/opt/local/bin/port load mysql55-serverSecure the server and set a new admin password:
/opt/local/lib/mysql55/bin/mysql_secure_installationCreate a configuration file:
cp /opt/local/share/mysql55/support-files/my-large.cnf /etc/my.cnf Edit /etc/my.cnf using your editor of choice and make the following changes to the [mysqld]:
- Change the maximum packet size to 16M:
max_allowed_packet = 16M
New time lapse video
Dan and I shot this last summer but it took a while to get it finished up. The next one is going to be even better.
Drupal on Lion (OS X 10.7)
I was half way done adding some info how to setup pecl/pear to my guide to running Drupal 6 on OS X 10.6 before I realized I'd been running Lion for almost nine months. So it seemed like a good excuse to update it for Lion. These might be a little wonky since I did an upgrade rather than a clean install so if you notice anything please drop me a line.
Note:I'll save you the trouble of commenting, I am familiar with MAMP but would rather punch myself myself in the face than use it. If you'd like to, go right, but I'm going to continue to compile my own so I know where everything ends up.
Working around "broken" RSS feeds
Found some more time to work on my fullfeeds project over the weekend. Finally getting into Node's everything happens in a callback spirit, and managing to not make it look like spagetti code. Discovering the async module really helped but I've probably gone a little overboard with it.
At this point it's following links, extracting and caching page content, and generating a new feed. But it's still got a way to go:
- The configuration is hard coded — I hope you like the feeds I'm interested in.
- It doesn't serve up its own feeds — on my server I symlinked its output directory into an Apache webroot to serve the files).
- Doesn't run as a service — I'm using cron to run it hourly.
Creating a sprite from cocos2d's CCTMXTiledMap
I'm working on a Pipe Mania/Dream clone for iOS using cocos2d. I was able to quickly implement the board using the CCTMXTiledMap component, but then when I started trying to figure out how to setup a sprite preview the next piece I got stuck. I'd intended to try to document all the false starts I took before figuring this solution out, but I waited too long before doing the writeup.

My map gets setup like this and I store a variable to make it easy to get to the board's layer where I'm placing the pieces:
CCTMXTiledMap *map = [CCTMXTiledMap tiledMapWithTMXFile:@"Board.tmx"];
CCTMXLayer *playLayer = [map layerNamed:@"Play"];
[self addChild:map z:-1];What I eventually figured out that I could just create my own texture from the layer's source image, then ask the layer which part of the texture the sprite should use:
CCTexture2D *tex = [[CCTextureCache sharedTextureCache] addImage:playLayer.tileset.sourceImage];
// Since I'm doing an 8-bit style I want it crisp and pixel aligned.
[tex setAliasTexParameters];
// We don't know what the piece is yet so just use the first tile.
CGRect rect = [playLayer.tileset rectForGID:playLayer.tileset.firstGid];
CCSprite *nextPiece = [CCSprite spriteWithTexture:tex rect:rect];
nextPiece.anchorPoint = CGPointZero;
nextPiece.position = CGPointMake(400, 224);
[self addChild:nextPiece];Then in my pickNextPiece method I can just adjust the rectangle:
// Pick a random tile...
nextTileGid = (arc4random_uniform(7)) + 2;
// Then ask the layer where the texture is.
CGRect rect = [playLayer.tileset rectForGID:nextTileGid];
[nextPiece setTextureRectInPixels:rect rotated:NO untrimmedSize:rect.size];