1. Ideas of March

    A year ago, I posted about Ideas of March, which Chris got rolling.

    In it, I pledged to blog more.

    Today, I am not so proud to say that I have mostly failed to do so. If I had to come up with a reason, I'd have to say that, personally, 2011 turned out a whole lot different than I was expecting, back then—and not in a good way.

    Over the last year, however, I did post a few things that I think were interesting, and worth of a re-read (at risk of making this post into a clip show):

    PHP Community Conference
    …a post about why I was excited about going to the PHP Community Conference in Nashville, last May. It turned out to be even better than I expected, and I'm really excited that plans are coming together for a 2012 edition.
    Gimme Bar no longer on CouchDB and Gimme Bar on MongoDB
    …a pair of posts describing some problems we had with CouchDB, and our smooth transition to MongoDB. We're still on MongoDB, and for the most part, I still really like it. I'd hinted about these posts in last year's Ideas of March post.
    Webshell
    …on Webshell which I still use almost daily, but has most certainly fallen out of a reasonable upkeep schedule. I really need to find some time to clean out the cobwebs. If you use HTTP and know JavaScript, you should check it out.
    Aficionado's Curse/Pessimistic Optimism
    …a post that I'm particularly proud of; mostly because I've finally managed to document (and coin a term, I hope) for why things seem so bad, but aren't actually so bad.
    HTTP/1.0 and the Connection header
    …finally, over Christmas, I managed to post about HTTP things (-:

    I was really hoping to do more. Last year, I suggested that I might turn my talk on Fifty tips, tricks and tools into a series of small blog posts, and I'd still like to do this. Hopefully in 2012. I also have a list of other things that I'm really interested in writing about. It's just matter of making time to do so. I plan to do that, this year. Starting with this post.

    I'd also like to get around to writing a thing or two about beer, this year…

    Much of what I said last year is still on my mind. I still miss the blogs we kept, 5+ years ago. Let's fix that.

    </navelgazing>

  2. Aficionado's Curse / Pessimistic Optimism

    As I've mentioned in previous posts, I like beer. I mean, I really like it. I've tasted many unique, special, rare, and extremely old beers. I even have Beer Judging credentials. I would go as far as to say that I'm a "beer aficionado." I find the idea of a cheap, poorly-made beer (especially when there are superior alternatives on hand) to be almost repulsive.

    I know aficionados in other fields: wine, vodka, scotch, cheese, movies, music, specific genres of music, woodworking, home electronics, office design, and even one guy I might consider a dog food aficionado.

    These people, like myself when it comes to beer, often suffer from what I call "Aficionado's Curse." This syndrome affects experts in many fields, and prevents them from truly enjoying the full gamut of their medium. They are able to truly appreciate the utmost quality, but are turned off by the bottom shelf. Others (non-aficionados) are perfectly happy consuming the most readily available items and occasionally treating themselves to something fancy from the middle.

    Consider someone who is completely immersed in the world of hand-made Swiss timepieces. Now, consider that person wearing a Happy-Meal-derived digital watch with a made-in-China plastic band. Unless they're trying to perfect their ironic hipster look, the cheap watch likely wouldn't fly.

    In high school, long before I considered that this thing might have a name, I had a media teacher who was a film aficionado. He once told our class "When you start making movies—no matter the length—your world will change. You will stop simply being entertained by what is on the screen before your eyes, and instead will wonder how they did that, or you might marvel at the complexity of a specific shot. You'll still enjoy film, but in a different way." This nicely sums up Aficionado's Curse.

    Maybe ignorance is bliss.

    In a phenomenon similar to Aficionado's Curse, I've noticed a trend that cloaks optimism in pessimism. Unfortunately, I am a victim of this, and I try to keep it reined in, but I often fail.

    I have very high expectations for things… nearly everything, in fact. I think that high expectations are generally a good thing, as so many things are—shall we say—of a quality less than the highest.

    I expect machines to work properly, traffic to flow, computers to perform at reasonable levels, food to taste good, service to be quick and friendly, events to respect their schedules and other similar things. More often than not, though, I am let down by this unmaintainable level of optimism. The bad part is that in my letdown, I often find myself complaining (or if I've managed to keep it under control, not complaining) about such things. Not because the thing I've just witnessed is completely broken, but more like because it's sub-optimal in some way. These complaints are (reasonably, I admit) perceived as pessimism. My optimism has precipitated as pessimism.

    I think this happens to smart people quite a bit. I've worked with people who are extremely unpleasant, but also extremely kind and forgiving. This may have been due to the scenario described above.

    I saw this on Fred Wilson's blog a while back, and I think it's relevant:

    "sometimes we make money with brilliant people who are easy to get along with, most often we make money with brilliant people who are hard to get along with, but we rarely make money with normal people who are easy to get along with."

    One of the greatest things I learned from Chris when working at OmniTI was something that he didn't intentionally teach me (at least not as part of my job): it's OK to be let down, but complaining about it doesn't often breed positive change. I've tried to apply this to my public persona in the past few years, and at risk of sounding like a complaint, I think we'd all do well to follow Chris's lead, and strive to be brilliant people who are also easy to get along with.

  3. Beer Alchemy Integration

    As I mentioned in my previous post, my beer recipes are now online.

    I've had several people ask me how this is done, so I think a post is in order.

    While it's entirely possible to brew beer at home without any fancy gadgets, there are several tools I use (such as my refractometer) that make the process easier, more controlled, or both. Brewing software is one of the few instruments that I'm not sure I'd want to brew without. I use a Mac, primarily, so Beer Alchemy (BA) is the obvious choice for recipe formulation, calculation, and logging.

    BA has its own HTML export mechanism for recipes, and I used this for quite a long time, but I was never really satisfied with the results. The markup was hard to style, contained a lot of clutter (occasionally useful, but often redundant information such as style parameters), and simply didn't fit well with the rest of my site.

    Beer Alchemy HTML Output

    You can also export from BA in PDF (not suitable for web publishing), ProMash's binary recipe format (a pain to convert, although there do seem to be some tools to help with this), BeerXML (normally the most accessible, but in my opinion, a poorly-designed XML format), or in BA's native .bar ("Beer Alchemy Recipe") format, which is what I chose.

    Beer Alchemy Recipe Export Dialog

    The bar format contains a property list, similar to those found throughout Apple systems. Property lists are either binary or XML (but the XML is very difficult to work with using traditional tools because of the way it employs element peering instead of a hierarchy to manage relationships). Luckily, I found a project called CFPropertyList that allows for easy plist handling in PHP. (I even contributed a minor change to this project, a while ago.)

    Once you've run the .bar file's contents through CFPropertyList, layout is very simple. Here's most of the code I use to generate my recipes:

    <?php
    $beerPath = __DIR__ . '/../resources/beer/';
     
    $recipes = apc_fetch('seancoates_recipes');
    $fromCache = true;
    if ($recipes === false) {
    	$fromCache = false;
    	foreach (new DirectoryIterator($beerPath) as $f) {
    		if ($f->isDot()) {
    			continue;
    		}
    		if (substr($f->getFilename(), -4) != '.bar') {
    			continue;
    		}
    		$cfpl = new CFPropertyList($beerPath . '/' . $f->getFilename());
    		$recipe = $cfpl->toArray();
    		$title = $recipe['RecipeTitle'];
    		$recipes[self::slugify($title)] = array(
    			'title' => $title,
    			'content' => $recipe,
    		);
    	}
    	asort($recipes);
    	if ($recipes) {
    		apc_store('seancoates_recipes', $recipes, 3600); // 1h
    	}
    }

    In addition to displaying the recipe's data, I also wanted to show the approximate (calculated) beer colour. Normally, beer recipes declare their colour in "SRM" (Standard Reference Method). There's no obvious, simple, and direct way to get from SRM (which is a number from 0 to 40—and higher, but above the mid 30s is basically "black") to an HTML colour.

    I found a few tables online, but I wasn't terribly happy with any of them, and keeping a dictionary for lookups was big and ugly. I like the way Beer Alchemy previews its colours, and since it has HTML output, I emailed the author to see if he'd be willing to share his algorithm. Steve from Kent Place Software graciously sent me an excerpt from his Objective C code, and I translated it to PHP. This might be useful for someone, and since Steve also granted me permission to publish my version of the algorithm, here it is:

    <?php
    /**
     * Calculate HTML colour from SRM
     * Thanks to Steve from Kent Place Software (Beer Alchemy)
     *
     * @param float $srm the SRM value to turn into HTML
     * @return string HTML colour (without leading #)
     */
    public function srm2html($srm)
    {
    	if ($srm <= 0.1) { // It's water
    		$r = 197;
    		$g = 232;
    		$b = 248;
    	} elseif ($srm <= 2) {
    		$r = 250;
    		$g = 250;
    		$b = 60;
    	} elseif ($srm <= 12) {
    		$r = (250 - (6 * ($srm - 2)));
    		$g = (250 - (13.5 * ($srm - 2)));
    		$b = (60 - (0.3 * ($srm - 2)));
    	} elseif ($srm <= 22) {
    		$r = (192 - (12 * ($srm - 12)));
    		$g = (114 - (7.5 * ($srm - 12)));
    		$b = (57 - (1.8 * ($srm - 12)));
    	} else { // $srm > 22
    		$r = (70 - (5.6 * ($srm - 22)));
    		$g = (40 - (3.1 * ($srm - 22)));
    		$b = (40 - (3.2 * ($srm - 22)));
    	}
    	$r = max($r, 0);
    	$g = max($g, 0);
    	$b = max($b, 0);
    	return sprintf("%02X%02X%02X", $r, $g, $b);
    }

    Here it is, in action, in JavaScript this time:

    SRM: =
     
  4. A new seancoates.com

    Over the past few weeks, my business partner Cameron and I have spent evenings, late nights, and weekends (at least partially) working on a much-improved seancoates.com.

    If you’re reading this via my feed, or through a syndication outlet, you probably hadn’t noticed.

    The primary goal of this change was to reduce (hopefully even remove) the ugliness of my main presence on the Web, and I’m very happy with the results.

    In addition to making things look nicer, we also wanted to improve the actual functionality of the site. Formerly, seancoates.com was a blog, with a couple haphazard pages thrown in. The new version serves to highlight my blog (which I fully intend to pick up with more frequency), but also contains a little bit of info about me, a place to highlight my code and speaking/writing contributions, and a good place for me to keep my beer recipes.

    Cameron came up with the simple visual design and great interaction design, so a public “Thank You” is in order for his many hours of thought and contribution. Clearly, the ugliness reduction was his doing (due to my poorly-functioning right brain).

    I’m very happy with how the site turned out as a whole, and thought I’d outline a few of my favourite bits (that might otherwise be missed at first glance).

    URL Sentences

    The technique of turning URLs into sentences was pioneered by my friend and colleague Chris Shiflett. Cameron (who shares studio space (and significant amounts of beer) with Chris) and I both like this technique, so we decided to implement it for my site.

    The main sections of the site are verbs, so this was pretty easy (once we decided on proper nomenclature). Here are a few examples:

    • seancoates.com/blogs – Sean Coates blogs…
    • seancoates.com/blogs/about-php – Sean Coates blogs about PHP (my “PHP” blog tag)
    • seancoates.com/brews – an index of my published recipes
    • seancoates.com/brews/coatesmeal-stout – the recipe page for Coatesmeal Stout

    To complement the URLs, the page title spells out the page you’re viewing in plain language, and the visual site header indicates where you are (while hopefully enticing you to click through to the other sections).

    Moving my blog from the root “directory” on seancoates.com to /blogs caused my URLs to break, so I had to whip up yet another bit of transition code to keep old links functioning. Even links on my original blog (which was hosted on blog.phpdoc.info) should still work. If you find broken links, please let me know.

    Vertical Content Integration

    My “/is” page contains feeds from Twitter and Flickr.

    The Twitter integration was pretty simple; I use the JSON version of my user feed, but I didn’t want to include @replies, so they’ve been filtered out by my code. If the fetch was successful, the filtered data is cached in APC for a short period of time so that I’m not constantly hammering Twitter’s API.

    Flickr’s integration was also very simple. After a run-in with some malformed JSON in their API, I decided to integrate through their Serialized PHP Response Format. The resulting data is also cached in APC, but for a longer period of time, as my beer tasting log changes much less frequently.

    Code Listings

    Displaying code listings on a blog isn’t quite as easy as it sounds. I recently had a discussion with a friend about redesigning his site, and he was considering using Gist from Github’s pastebin-like functionality. Doing so would have given him easy highlighting, but one thing he hadn’t considered was that his blog’s feed would be missing the embedded listings (they come from a third party, and wouldn’t actually appear in his feed’s data stream).

    Another problem we faced was one of space. While I often try to keep code to a maximum of 80 (or slightly fewer) characters wide, this isn’t always possible. Injecting a line break into the middle of a line of code is risky, especially for things like SSH keys and URLs. This problem is usually solved by setting the content’s CSS to overflow: scroll, but that littered Cameron’s beautiful design with ugly platform-specific scroll bars. “Clever” designers and developers sometimes overcome this by implementing “prettier” scroll bars, but I’m strongly against this behaviour, so I wouldn’t have it on my site.

    I’m quite happy with our eventual solution to this problem. Now, when a blog post contains code that extends beyond the normal width of the blog’s text, the right-most part of the text fades to white, and the listing is clickable. Clicking expands all listings on the page to the minimum width that will accommodate all embedded code.

    Here's some example code that stretches much wider than this column would normally allow.
    Injecting line breaks is dangerous. Here's why: http://example.com/obviously/not/a/sentence/url
    Breaking that in the middle is far from ideal.

    jQuery saved me hours of development work here, and I couldn’t recommend it more highly. Highlighting is provided by a plugin that I wrote a couple years ago. It uses GeSHi to highlight many languages. I’ve never been very happy with GeSHi’s output, but it’s Good Enough™ until I can find time to implement a better solution that uses the Tokenizer for PHP.

    Software

    In addition to PHP, this site integrates a custom version of Habari, with our own theme and plugins. One of those plugins allows me to keep my blog posts in HTML files in my Git repository, to make for much easier editing, greping, etc.

    Everything except /blogs was built within the Lithium framework. It handles all of the boring stuff like controllers, routing, and templates, so I didn’t have to write that code myself (which I find incredibly boring these days).

    Hashgrid was invaluable in ensuring that the site aligns with a visual grid (again, thanks to Cameron’s meticulous expertise). Pressing your g key will show the grid he used. I even made a few improvements to how Hashgrid works, which I hope to eventually see in the master branch.

  5. Post-ConFoo

    Today I am back in the (home) office after speaking at ConFoo last week.

    I gave two talks:

    Despite some timing issues (as is always the case for me with new talks), I think both sessions went well. I got some good, constructive feedback from attendees on how the talks could be made better, and if I get the opportunity to give them again, I'll definitely take it into consideration.

    Because PSAV (not the conference organizers' fault, other than trusting PSAV—a lesson all conference organizers eventually learn) was its normal bucket of fale, conference Internets weren't exactly usable. I was lucky enough to be in my home country (for a change), so I was able to tether on 3G for most of the week, and that kept me and a few others online. However, I think that most attendees didn't have the same opportunity, so if you attended one of my talks, I'd greatly appreciate it if you could head over to joind.in and post a comment or two about what you thought (talk-specific links above).

    After the conference ended, Andrei stayed at my place.

    On Saturday, we brewed a second annual batch of Белый, which—if all goes well—will end up at 11.5%ABV. Maybe it will be ready for next year's ConFoo. (-:

    We decided to take it easy on Sunday… sort of. We spent most of the afternoon planning out a PHP extension we'd been talking about for several months: a highly-customizable and user-hookable PHP preprocessor. Afternoon turned to evening, turned to night, and by the time we turned in, we had a working—but not yet ready for release—extension. More details to come, but here's a teaser.