Everything I learned to manage my career I learned from Soccer

This was originally posted on the mojolive blog 5 years ago, but I want to preserve it here if/when it goes down.

When I started working as a web developer, there wasn’t a lot of guidance about what that meant as a career choice. Of course, back then we were getting over the excitement of the blink tag and the new design opportunities afforded by table tags. I had to figure out a career path, and I did manage to do just that by watching a lot of soccer.

1. It’s not a solo effort.

Rare is the player that can take the ball from one end line, dribble past 11 opponents, and score the winning goal. Even if they manage to do it during a game, they’re likely to use their hand to score the next goal.

It is tempting to think of your career as a solo effort, particularly in technical fields where introverts seek shelter. But the people you work alongside, meet at conventions, and connect with can be invaluable resources when you’re looking for the next challenge in your career. Even at a small company, you’ll have to work alongside other programmers, manager, designers, and end users.

It pays off to make the effort and get to know them beyond the current project, I wouldn’t be working at mojoLive if I hadn’t worked with Sandy previously. Take part in your local community events and conferences too, they’re great for expanding your network’s reach outside of colleagues, schoolmates, and clients.

2. Serendipity complements planning

When you’re watching a game, and maybe dreading a scoreless tie, the entire game can change instantly.  A player with a simple flick, a mazy dribble, or an audacious goal can change the tempo and momentum of the rest of the match.  It’s impossible for a soccer coach to plan every movement or play, like an American football or baseball manager.

It’s also impossible to plan every single move in a career, no matter how good your plan is; economic conditions can change and new technologies may become popular. You have to leave room for chance and serendipity to play a part in your career, and be willing to take a risk and make a change when an opportunity presents itself.

3. Keep your skills sharp

Once a player passes 30 years old, fans and coaches inevitably start asking how much longer they can play. Like any other athlete, the shelf life of a soccer player is limited by his physical condition. Some players can defy time; Preki was named Major League Soccer’s MVP at the ripe old age of 40.

For most of us, physical traits don’t affect our job performance so drastically. But, your own shelf life is limited by the skills you acquire and use each year. If you find yourself in a rut, using the same programming language all the time, one technology stack, or targeting a single platform, make it a point to look outside your comfort zone.

4. The good players practice, practice, practice

The best players have an almost single-minded focus on soccer. It might make them dull at dinner parties but it gives them an edge. They spend extra time after practice running through drills on their own, or hitting the gym on their off days.

Likewise, extra-curricular projects can help you learn something new. Always building Drupal sites? Check out python and django. Have an idea that could be a useful product? Build it in your spare time, to see just what it takes to build something from start to finish.

5. Play with the best to get better

I came to the game late and only started playing soccer recreationally in college. I quickly learned that playing with better players made me improve faster. Not that I ever became more than a barely adequate player, but playing with them meant I had to try to be quicker, and play smarter.

Once you find a comfort zone, it’s tempting to stay in it but you risk stagnation. If you find that you’re a big fish in a little pond or you’re a little bored with the work you’re doing, its time to think about working on more ambitious projects. For programmers, a ready avenue to collaborate with other top-notch developers is through open source projects, or simply sharing code on github.

6. Don’t be a one trick pony

It seems every team has at least one player who is one dimensional but the coach loves for some reason. The worst is watching a player who can only shoot with his left foot. Inevitably, they’ll be one-on-one with the goalkeep, but the ball will be on their right foot.  As they waste time maneauvering to get the ball on their favored left foot, a defender has time to recover and tackle the ball away.

Don’t be predictable. Don’t stick blindly to always using the same solution whether its PHP, Drupal, or jQuery. For some projects, you’ll waste time trying to fit a square peg into a round hole, when a faster, cheaper solution. It’s also tempting to think of yourself as a “Back-end programmer” or a “Front-end engineer”. Learning to do both not only improves your versatility, but you can speak intelligently about what it takes to do both.

20 Years of PHP

Ben Ramsey shared how he got started with PHP and had the great idea of asking others to write about their stories and tagging it as #20yearsofphp. This is my story.

When I graduated from college in 2000, I began looking for a job without a clear idea of what I wanted to do. In grad school I had done some projects using HTML, ASP, and ShockWave for various professors and figured I could get a job building web sites until I decided on something. I replied to a job posting (I think it was on hotjobs.com) and in September 2000 I started working as a web developer at Forum One. Thanks to that job, I spent a week working in San Francisco after meeting my (future) wife on a previous trip to California. We’d get married in 2004.

At the time, PHP4 had just been released. I worked on projects which still used PHP3, or interfaced via Perl CGI scripts to save data in a custom-build in-house CMS. I think my first actual PHP project was for a local Jewish Temple. Like other junior devs at that job, I took a shot at replacing the Perl scripts with my own PHP versions. Luckily, I never inflicted them on my colleagues.

From there, PHP was a gateway to learning about Linux, web servers, databases & SQL, and so much more. Thanks to PHP (and Drupal) I worked for my favorite soccer team, D.C. United. Today I’m grateful that, through running php[architect] I get to work not only with Eli, Kevin, Sandy, and Heather on daily basis but also with the wider PHP community through php[architect]’s magazine, books, and conferences.

I don’t think I could have planned the last 15 years better. Here’s to the next 20!


Why global variables are bad

This question came up yesterday when Sandy and I presented at DC Web Women, an Introduction to  PHP [slides]. I couldn’t come up with a coherent set of arguments at the time, in a way that I could explain easily. These posts do a better job, first a general programming article on the subject:

Implicit coupling — A program with many global variables often has tight couplings between some of those variables, and couplings between variables and functions. Grouping coupled items into cohesive units usually leads to better programs.

From: Global Variables Are Bad

And a PHP specific article full of excellent examples

You may have heard that globals are bad. This is often thrown around as programming gospel by people who don’t completely understand what they’re saying. These people aren’t wrong, they just don’t often program what they preach. I’ve lost track of the number of times I’ve had the “globals are bad” conversation with someone (and been in agreement) only to find their code is littered with statics and singletons. These people are confusing globals (as in the $GLOBALS array) and global state.

From: Why global state is the devil, and how to avoid using it – TomNomNom.com

Remove unapproved comments from WordPress exports

Recently, I needed to migrate some WordPress blogs to another system. WordPress provides a handy way to export content in its WXR format. However, it’ll export all comments, whether approved or not. This is good from a data backup standpoint, but I didn’t need to import these. They were also bloating the XML file and affecting how long it took my import to process.  I needed a way to remove unapproved comments, the following code will do that using PHP’s DOMDocument extension to walk an input file. The cleaned up content is sent to STDOUT so you can pipe it to another file to save.

if (!isset($_SERVER['argv'][1])) {
    echo "\nSpecify input file \n";

$infile = $_SERVER['argv'][1];

$doc = new DOMDocument();
$doc->recover = TRUE;

$comments = $doc->getElementsByTagName('comment');
$to_remove = array();

foreach ($comments as $comment) {
    if ($approved = $comment->getElementsByTagName('comment_approved')) {
        if ($approved->length > 0) {
            $app = $approved->item(0);

            // can't remove nodes while looping
            if (0 == $app->nodeValue) {
                $to_remove[] = $comment;

if (count($to_remove)) {
    foreach ($to_remove as $elt) {

$doc->formatOutput = true;
$doc->preserveWhiteSpace = false;
echo $doc->saveXML();

Extract images from an HTML snippet

The function here will take an HTML fragment and return an array of useful images it finds.

 * extractImages
 * @param $text
 * @return array|bool
function extractImages($text)
    $header = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
    $text = $header . $text;
    $dom = new DOMDocument();
    if (@$dom-&gt;loadHTML($text)) {
        $xpath = new DOMXpath($dom);
        if ($images = $xpath-&gt;evaluate("//img")) {
            $result = array();
            foreach ($images as $i =&gt; $img) {
                $ht = $img-&gt;getAttribute('height');
                $wd = $img-&gt;getAttribute('width');
                // if height &amp; width are 1 its a bug, ignore
                if (1 === (int)$ht &amp;&amp; 1 === (int)$wd) {
                // if it doesn't end in an image file extension
                // then ignore
                $src = $img-&gt;getAttribute('src');
                if (!preg_match('/.(png|jpg|gif)$/i', $src)) {
                // do we need to figure out the full url to the image?
                if (!preg_match('/^https?:///', $src)) {
                $alt = $img-&gt;getAttribute('alt');
                $result[$i] = array('src' =&gt; $src, 'alt' =&gt; $alt, 'height' =&gt; $ht, 'width' =&gt; $wd);
            if (!empty($result)) {
                return $result;
    return false;

Fix SSL timeouts with the Facebook PHP-SDK

I ran into SSL timeouts on in local development setup when I was re-factoring some integration code with facebook and using their SDK. It was tricky to diagnose, I was sure that my changes couldn’t be the cause, and I finally confirmed it by running our production codebase. Since it was having the same timeout error, I knew the bug had to be in an underlying layer.

For the record, I’m running this version of curl on my Archlinux box:

<code>curl 7.25.0 (x86_64-unknown-linux-gnu) libcurl/7.25.0<br /> OpenSSL/1.0.1 zlib/1.2.6 libssh2/1.4.0

I also got the error from the command line with

<code>curl "https://graph.facebook.com/oauth/access_token"

But it is fixed with

<code>curl --sslv3 "https://graph.facebook.com/oauth/access_token"

Debian Server

On a debian squeeze server, with the latest (4/3/2011) version of curl:

<code>curl 7.21.0 (x86_64-pc-linux-gnu) libcurl/7.21.0<br /> OpenSSL/0.9.8o zlib/ libidn/1.15 libssh2/1.2.6

The timeout does not happen with either of the following commands:

<code>curl "https://graph.facebook.com/oauth/access_token"
curl --sslv3 "https://graph.facebook.com/oauth/access_token"


The time out does not happen on OS X which runs curl 7.21.4


So, this timeout only seems to affect users with very new version of curl. Fixing it requires adding a line to the Facebook PHP SDK, which while minor, you have to remember if you ever upgrade it. At the same time, this bug could come back and bite you down the road if your operating system sneaks in a newer version of curl. You can see a fork of the PHP SDK with this fix on github.

Other references:

  1. Facebook bug ticket
  2. Maybe related PHP bug

Drupal: Invoke blocks and views from code

While Panels is great for controlling the layout of drupal pages, there are times when you can’t use the module to theme a page.  For uncached content, it does introduce some performance overhead into the drupal request change.  It can also be tedious to migrate changes from one environment to the other if you don’t export pages and variants to version control.

When you’re working in the stock theme layer, the following functions can come in handy.

Render a Block

   * Convenience function to easily call a block from a module
   * @param string module name
   * @param string delta
   * @return array block
  public function invoke_block($module, $delta) {
    if ('block' == $module) {
      global $theme_key;

      // the block_block view is pretty useless
      $block = db_fetch_object(db_query("SELECT b.*, bl.title, bl.*
                   FROM {boxes} b
                   INNER JOIN {blocks} bl ON (bl.module='block'
                       AND bl.delta=b.bid AND bl.theme='%s')
                   WHERE b.bid = %d", $theme_key, $delta));
     $data['subject'] = $block-&gt;title;
     $data['content'] = check_markup($block-&gt;body, $block-&gt;format, FALSE);

      if ('n/a' !== $data['content']) {
        return ($object) $data;
    } else {
      if (module_exists($module)) {
        $block =  module_invoke($module, 'block', 'view', $delta);
        $block['delta'] = $delta;
        $block['module'] = $module;
        return (object) $block;
      else {
        trigger_error("Module $module is not enabled.", E_USER_ERROR);

To show block with delta 1 defined by module foo:

$block = invoke_block('foo', 1);
$output = theme('block', $block);

Render a View

   * Convenience function to easily get the output of a view
   * A note about the display id, this is NOT the identifier
   * that you can set in the Views UI. To see the display id, look
   * at the theme information for the display.  For blocks it will
   * be something like block_1 or block_X where X is a number.
   * If the display_id doesn't match then Views automatically
   * uses the default display which can make themeing a pain.
   * modeled on view_embed_view().
   * @param string view name
   * @param string display name (see theme info for the display name)
   * @param array additional options
   * @return string
  static public function invoke_view($name, $display_id = 'default') {
    $args = func_get_args();
    array_shift($args); // remove $name

    if (count($args)) {
      array_shift($args); // remove $display_id

    $view = views_get_view($name);
    if (!$view) {
      trigger_error('Unknown view invoked: ' . $name, E_USER_WARNING);

    // validate the $display_id is valid
    // generate an error to prevent wasted time debugging.
    $defined = array_keys($view-&gt;display);

    if (!in_array($display_id, $defined)) {
      trigger_error('In view "' . $name . '" unknown display invoked "'
                  . $display_id . '"', E_USER_WARNING);

      // lets not render, chances are we don't want
      // the default display if we invoke a specific view

    // if a view is empty, dont return anything
    $r = $view-&gt;preview($display_id, $args);
    if (false !== strpos($r, '
‘)) { return $r; } else { return null; } }

To render display page_1 from view foo. You can even pass arguments to the view.

$output = invoke_view('foo', 'display1');
$output2 = invoke_view('foo', 'display1', 2010, 111); // with args!