Thoughts, rants and commentary from a husband, father of five and professional web geek

Setting up a multidimensional and accessible configuration object/class

Posted on August 19th, 2008 in PHP, Programming, Web Development | 4 Comments »

For the last few days I have been struggling, sort of, to find the best way to implement a configuration class or object that will allow me to continually append values to it and allow easy access to the members of it. Think of it as a sort of data store that houses multi-tiered data that is logically structured. For example, lets say I have a configuration array like this:

<?php
$array = array(
	'defaults' => array(
		'page' => 'index',
		'action' => 'default',
	),
	'routes' => array(
		'controller', 
		'view', 
		'model',
	),
	'application' => 'Bilbo',
	'nested' => array(
		'levels' => array(
			1 => 'floor',
			'garage',
			'canopy',
		),
		'names' => array(
			1 => 'Hectar',
			'Jonas',
			'Phil',
		),
		'named' => array(
			'floor' => 'Hectar',
			'garage' => 'Jonas',
			'canopy' => 'Phil',
		),
	),
);
?>

And lets say that this array is parsed into a config object that is in essence an interface so that config params can be set and got from it. The config array itself is protected so it cannot be manipulated directly (because seriously, why should you be able to manipulate configuration settings directly?). What if I wanted to find the value for $array['defaults']['page']? Without being able to access the array directly you cannot easily do this without writing function that would somehow recurse the array until it finds the correctly nested key that matches you request and returns its value, if it is found.

That is one idea. And I tried that. A lot. And as I went through trying that I began to realize that if I have a 200 member config array (say it has been continually built up) and I am accessing that from 20 different sources per application (think a framework hitting itself and a framework-hooked client hitting it as well) the the config array would essentially be traversed for each request coming in to the object. As I thought about this I began to think that it might be easier to traverse the array once and set the array into a levelized series of keys and values that map to each level of the config array so that a simple request to something like config::fetch('defaults:page'); would return ‘index’ (based on our example array).

So I set out to do that and I came up with something that has been immeasurably useful to me already. Essentially it is a class that allows for the setting of config parameters into the class in a way that makes each level accessible by its current location in the tree, separated by a delimiter (in my case the colon ‘:’). I know the following code needs a little more love, but it is doing what I want it to at the moment (I will be making changes that allow setting a custom delimiter and the whatnot):

<?php
/**
 * Padlock - The PHP Application Developer's Library of Objects and Code Kits
 * 
 * @category Padlock
 * @package Padlock
 * @author Robert Gonzalez <robert@everah.com>
 * @license PLEASE SEE ACCOMPANYING LICENSE TEXT OR THE {@see Padlock::license()} method
 * @version $Id: Config.php 33 2008-08-20 06:30:39Z robert $
 */
/**
 * Padlock Configuration object abstract
 * 
 * The Padlock Configuration object handles parsing of initial framework instructions
 * and individual configuration items. This class is designed to be extended by
 * concrete classes that are specific to a particular type of config implementation.
 * 
 * @author Robert Gonzalez <robert@everah.com>
 * @category Padlock
 * @package Padlock
 * @version @package_version@
 */
abstract class Padlock_Config {
	/**
	 * String type config param constant
	 */
	const CONFIG_TYPE_STRING = 'string';
 
	/**
	 * Array type config param constant
	 */
	const CONFIG_TYPE_ARRAY = 'array';
 
	/**
	 * Object type config param constant
	 */
	const CONFIG_TYPE_OBJECT = 'object';
 
	/**
	 * Flag that tells the configuration class whether to merge new values or not
	 * 
	 * @access protected
	 * @var boolean
	 */
	protected static $_merge = true;
 
	/**
	 * The framework configuration array
	 * 
	 * @access protected
	 * @var array
	 */
	protected static $_config = array();
 
	/**
	 * The framework configuration array in the raw
	 * 
	 * @access protected
	 * @var array
	 */
	protected static $_configRaw = array();
 
	/**
	 * Object constructor
	 * 
	 * This is final and private - basicaly this class is meant to never be 
	 * instantiated.
	 * 
	 * @access private
	 */
	final private function __construct() {
		trigger_error('The Config object cannot be instantiated', E_USER_ERROR);
	}
 
	/**
	 * Abstracted child method that requires definition within child classes
	 * 
	 * @access public
	 * @param mixed $config Source of the configuration collection
	 */
	abstract public static function setFrom($config);
 
	/**
	 * Sets up and loads a configuration collection into the framework
	 * 
	 * If the $config param is an array the array will be loaded into the config
	 * class as a merge. It was also be traversed and exploded out into each 
	 * component of the array as a map to the end element value of the array 
	 * path.
	 * 
	 * If the $config param is an object the object will be traversed as an 
	 * array and set into the config class as an array and a mapped array.
	 * 
	 * If the $config param is a string it will be treated as though it were a 
	 * file name and handled accordingly.
	 * 
	 * @access public
	 * @param mixed $config Configuration to process
	 */
	public static function setup($config) {
		switch(gettype($config)) {
			case self::CONFIG_TYPE_ARRAY:
			case self::CONFIG_TYPE_OBJECT:
				Padlock_Config_Array::setFrom($config);
				break;
 
			case self::CONFIG_TYPE_STRING:
				Padlock_Config_File::setFrom($config);
				break;
		}
 
		// Set it now
		self::_setConfig(self::$_configRaw);
	}
 
	/**
	 * Appends the config setup with more config params
	 * 
	 * @access public
	 * @param array $config More config params to set, in the form of an array
	 */
	public static function append($config) {
		self::_setRaw($config);
		self::_setConfig(self::$_configRaw);
	}
 
	/**
	 * Sets a single config property and value
	 * 
	 * This method will not set null values as null values have special meaning
	 * throughout the framework. Essentially if the value is null then it means
	 * there is no known config setting for the name/property. Nulls are returned
	 * when names/props cannot be found.
	 * 
	 * @param string $name Config property to set
	 * @param mixed $value Value for this config property
	 */
	public static function set($name, $value, $merge = true) {
		/**
		 * Before anything we do we must check a value. 
		 * 
		 * Null values are special to the config class in that a NULL will be 
		 * literally translated to nonexitence. So if the value being passed is 
		 * null any searching for it will return null anyway.
		 */
		if ($value === null) {
			return false;
		}
 
		/**
		 * If we are merging OR if the config item is not currently set then we 
		 * handle that first and call it done.
		 */
		if ($merge || self::$_merge || !self::has($name)) {
			self::append(array($name => $value));
			return true;
		}
 
		/**
		 * The only this could mean is that the value is null or the name 
		 * already lives and is not being merged.
		 */ 
		return false;
	}
 
	/**
	 * Checks existence of a config property
	 * 
	 * This will return true for null values of a property. This might appear
	 * counterintuitive until you consider that we are just checking if there
	 * is a property set in this object. Yes, the property can be set as a false
	 * or a null. It will be without value, but it will be set, which is what 
	 * we are asking about.
	 * 
	 * @access public
	 * @param string $name Config property to check
	 * @return boolean True if set, false otherwise
	 */
	public static function has($name) {
		return is_string($name) && array_key_exists($name, self::$_config);
	}
 
	/**
	 * Gets a property value
	 * 
	 * @access public
	 * @param string $name Property to get the value for
	 * @return mixed
	 */
	public static function get($name) {
		// Return what is being asked for, or null
		return self::has($name) ? self::$_config[$name] : null;
	}
 
	/**
	 * Fetches the entire configuration array from this class
	 * 
	 * This is a useful convenience method meant to allow the fetching of the 
	 * config settings array and use outside of this class. It can also be used 
	 * to set these configs into other objects.
	 * 
	 * @access public
	 * @return array Entire configuration array
	 */
	public static function fetch() {
		return self::$_config;
	}
 
	/**
	 * Tells the class to turn merging of values on or off.
	 * 
	 * This can be useful when the need to override or not override comes up as 
	 * this method allows for changing of the config merge argument. By default 
	 * this class will merge all set values.
	 * 
	 * @access public
	 * @param boolean $on Flag setting to pass to the class
	 */
	public static function setMerge($on = true) {
		self::$_merge = (bool) $on;
	}
 
	/**
	 * Sets a series of properties from an array of properties
	 * 
	 * @access protected
	 * @param array $source Array to set values from
	 * @param string $key Name of the key to append to the config stack
	 */
	protected static function _setConfig($source, $key = null) {
		// This should only be pushed if there is an array that isn't empty
		if (is_array($source) && !empty($source)) {
			// Loop through the array and start setting stuff
			foreach ($source as $k => $v) {
				/**
				 * This is where the setting magic takes place, putting the 
				 * hierarchy together for the entire config tree.
				 */
				$newkey = $key === null ? $k : "$key:$k";
 
				// Set the new values into the config
				self::$_config[$newkey] = $v;
 
				// Run through this process again until we need not do this
				self::_setConfig($v, $newkey);
			}
		}
	}
 
	/**
	 * Sets the raw config array data for use later, if it is needed
	 * 
	 * @access public 
	 * @param array $config Config array to set into the raw array
	 */
	protected static function _setRaw($config) {
		if (is_array($config) || is_object($config)) {
			self::$_configRaw = array_merge(self::$_configRaw, (array) $config);
		}
	}
}

You might notice that the method Padlock_Config::setup() is where everything takes place. Because this is essentially a deciding method I have included the Padlock_Config_Array class so you can see what happens when you load an array into the Padock_Config class for setting.

<?php
/**
 * Padlock - The PHP Application Developer's Library of Objects and Code Kits
 * 
 * @category Padlock
 * @package Padlock_Config
 * @author Robert Gonzalez <robert@everah.com>
 * @license PLEASE SEE ACCOMPANYING LICENSE TEXT OR THE {@see Padlock::license()} method 
 * @version $Id: Array.php 32 2008-08-20 00:59:12Z robert $
 */
/**
 * Padlock Configuration Array handler class
 * 
 * The Padlock Configuration Array handling class handles setting of config params 
 * from an array. The nature of this handler builds the configuration array into
 * tiers that are made up of other segments of the initial data set so that the
 * hierarchy of config elements is easily fetched.
 * 
 * @author Robert Gonzalez <robert@everah.com>
 * @category Padlock
 * @package Padlock_Config
 * @version @package_version@
 */
class Padlock_Config_Array extends Padlock_Config {
	/**
	 * Sets a series of properties from an array of properties
	 * 
	 * @access public
	 * @param array|object $config Array or object to set values from
	 */
	public static function setFrom($config) {
		self::_setRaw($config);
	}
}

Please keep in mind a few things about this: 1) I have an autoload method registered in the Padlock superclass that handles loading of support files, so you won’t see includes and requires anywhere in here, and 2) The file class has considerably more code than the array class.

To use this, all you do is create your array and pass that to the Padlock_Config::setup() method. After that you can use Padlock_Config::get('path:to:a:nested:config') to get to one, or use Padlock_Config::fetch() to get all of them in the config class’ core config array. For reference, that array would now look like:

array(21) {
  ["defaults"]=>
  array(2) {
    ["page"]=>
    string(5) "index"
    ["action"]=>
    string(7) "default"
  }
  ["defaults:page"]=>
  string(5) "index"
  ["defaults:action"]=>
  string(7) "default"
  ["routes"]=>
  array(3) {
    [0]=>
    string(10) "controller"
    [1]=>
    string(4) "view"
    [2]=>
    string(5) "model"
  }
  ["routes:0"]=>
  string(10) "controller"
  ["routes:1"]=>
  string(4) "view"
  ["routes:2"]=>
  string(5) "model"
  ["application"]=>
  string(5) "Bilbo"
  ["nested"]=>
  array(3) {
    ["levels"]=>
    array(3) {
      [1]=>
      string(5) "floor"
      [2]=>
      string(6) "garage"
      [3]=>
      string(6) "canopy"
    }
    ["names"]=>
    array(3) {
      [1]=>
      string(6) "Hectar"
      [2]=>
      string(5) "Jonas"
      [3]=>
      string(4) "Phil"
    }
    ["named"]=>
    array(3) {
      ["floor"]=>
      string(6) "Hectar"
      ["garage"]=>
      string(5) "Jonas"
      ["canopy"]=>
      string(4) "Phil"
    }
  }
  ["nested:levels"]=>
  array(3) {
    [1]=>
    string(5) "floor"
    [2]=>
    string(6) "garage"
    [3]=>
    string(6) "canopy"
  }
  ["nested:levels:1"]=>
  string(5) "floor"
  ["nested:levels:2"]=>
  string(6) "garage"
  ["nested:levels:3"]=>
  string(6) "canopy"
  ["nested:names"]=>
  array(3) {
    [1]=>
    string(6) "Hectar"
    [2]=>
    string(5) "Jonas"
    [3]=>
    string(4) "Phil"
  }
  ["nested:names:1"]=>
  string(6) "Hectar"
  ["nested:names:2"]=>
  string(5) "Jonas"
  ["nested:names:3"]=>
  string(4) "Phil"
  ["nested:named"]=>
  array(3) {
    ["floor"]=>
    string(6) "Hectar"
    ["garage"]=>
    string(5) "Jonas"
    ["canopy"]=>
    string(4) "Phil"
  }
  ["nested:named:floor"]=>
  string(6) "Hectar"
  ["nested:named:garage"]=>
  string(5) "Jonas"
  ["nested:named:canopy"]=>
  string(4) "Phil"
}

I hope this is useful for someone in some capacity. I played with this for a little while before getting it right. But now it is something that I am using all over the place.

Good luck with your coding and happy PHPing (did that sound weird or what?)!

Back to top

I thought this was taken care of already

Posted on August 18th, 2008 in Geek Stuff, Personal Messages, Rants | No Comments »

Remember last week me talking about how the bandwidth provider for my company decided to be just plain stupid and put the screws to my company, thus ensuring we would hate them forever? Guess what? They weren’t finished.

This morning, as I was walking out the door, literally, with one foot on my patio, I get a call from my boss. It went something like this:

He: “Did the domain transfer screw up our network name resolution?”
Me: “Not that I can think of. Let me check the transfer status.”
He: “Because we have no communication, again. No email, no web, no vpn.”
Me: “It looks like the domain name is still in the previous registrar approval phase. I am not sure what is causing our outage.”
He: “Could you call our sys admin to see if you can figure out what is happening. Right now we have no email, no web, no vpn.”
Me: “Sure thing, let me call him.”

I called my guy and together we came upon something a little different from the last outage last week. We started with our normal troubleshooting techniques: ping, tracert, dig. Very quickly we came to the conclusion that our DNS was not resolving again for some reason. The only difference between this time and the last time was that this time the DNS servers were not responding at all to our requests. I called my boss back and told him that I had given our sys admin the name and number of someone to talk to, even though my attempt at calling him was an epic fail. The phone went to voice mail, but they have not message center so I could not leave a message. Instead I was transferred to the switchboard where I was told that there is no known number and I was hung up on. Nice.

Knowing that my hands were tied at home I told my boss I would be in shortly and began my drive to work. When I got in about 30 minutes later my boss was on the phone. Wanna know with who? You guesses it. Our bandwidth provider.

Now I know you want to know this. What was the cause of this outage? Was it a catastrophic failure of a hard drive? Perhaps a full blown upstream network outage? Maybe a power outage? No. You’re going to love this…

We didn’t pay our bill.

What? Wait, we just took care of that last week didn’t we? Apparently not. See, the email that contained the invoice we were supposed to pay from never sent. Their paper invoice printing system has been offline for a few months so they could not send us a paper invoice. And apparently it was not noted anywhere in our account that we had spoken to their highest level AP person who had assured us that our services would not be terminated again. With that, someone who saw that our account was past due decided to pull our plug all over again.

Are there any further lessons to learn from this? Sure. Try not to be stupid more than once in a given weeks period of time. I tend to think that if that company were a person my boss would have driven to that person’s house and kicked that person’s butt halfway across their bandwidth pipe. Which might not be as far as I think seeing as they are now pretty much nothing more than a name and a phone number. That doesn’t allow messages or actually route to anyone.

Back to top

Work it like a man

Posted on August 17th, 2008 in For the men, Personal Messages | No Comments »

Oh that I would be a man and do the things that men do.

Robert Gonzalez

I have so wanted, as of late, to stop being a wimpy, cowardly, weak male and become the strong, dominating, adventurous, aggressive man that I was created to be. And for the most part I have begun this transformation, authoritatively, taking back what I should never have surrendered to begin with. And I have found that with this step toward exercising my authority, dominance (as a person, not as a man over someone) and power that I have also been faced with challenges designed to poster me to to that very thing.

What I mean by that is that I have felt the need recently to display my strength to myself. My physical strength, the stuff that comes out of the broad shoulders, large legs and muscles that God gave me. As I man I have been created strong and I believe that is for a purpose. But a purpose in design is nothing more than an idea if it is not put into practice. It is my intention to put my design into practice as often as I can and with that shatter the notion of what I used to be when being a man was not a priority to me.

To that end I have decided recently that I needed to begin the handle the management of the finance in our home. If you have ever read any of my more recent entries you would know that our finances are pretty unstable right now. There are a number of reasons for this and to be honest, I do not see Sandi handling the finances as a reason at all. I would say that any real man would take responsibility for ceding that role to his wife.

Now hear me as well as you can… I am not saying a woman cannot handle finances. Lord knows there are plenty of men out there that have put their women necessarily into the position of financial manager of the home. But I have to say that even though my wife is skilled at handling a checkbook and several bank accounts, it is my calling as the head of our home to handle that, very often stressful, responsibility. I am the hunter, the gatherer, the conqueror, the killer. My wife is the preparer, the tender, the handler of the kill. Together we are the consumers of both my work and hers. I believe it is my role to ensure that my wife has all of the tools the she needs to do her work adequately and effectively. It is my place as a builder to build her a platform upon which she can live out her calling.

To that end I am now in charge of management of the finances. Not blindly and in complete isolation. To the contrary, we are both involved intimately in the finances, we both know where we stand daily and we both are aware of what is coming up. The difference now is that I am making the hard, sometimes painful decisions that were really entirely too heavy a burden for my wife to carry for so long and she is supporting me in that.

So after church this morning my wife gave me some time alone to get the finances and accounting log in order and then we talked about it. I had to come to some pretty hard decisions and some pretty inevitable conclusions, but it felt good to do something I am supposed to do. Even Sandi told me that she is feeling better with this change. How can you not when you begin to fulfill your purpose?

Later on during the day I was working on something for a client. Lord knows we need the money something awful and this project has gotten so sidetracked by things in my personal life and the busy-ness of my client. It needs to be done, both the work and the project, and I need to get it done. I am a worker and builder after all. This is what I do. And I was doing it. And something came up. Something that needed my manliness at that moment.

My two older daughters’ bunk beds needed to be put together.

One of the funnest things a man can do is use tools of any sort and physical strength to forcible manipulate those tools. We love that kind of stuff. So much so that some men go into trades that require that daily. My friend Ray is a prime example. He is millwright. He gets to break stuff, build stuff, work on stuff, work with tools, get dirty, get bloody knuckles… the full gamut, daily. I write web applications. I still get to use tools, but not the kind that put the feel of cold steel into a burly hand and demand that the steel be wielded. So when I get that chance I run to it.

I was able to take apart my two daughters’ beds and reassemble them in a way that allowed me to stack them. The I had to assemble the rails and what not so that Sarah doesn’t fall on her face in the middle of the night. Then, the coup de grâce was that I had to coordinate the lifting of the upper bed onto the lower bed and move the assembled bunk into position on the wall that we decided to put it on. Outstanding. I haven’t worked like that, physically, in a long time. And it felt great.

After this I was a little tired (from waking up early primarily, I will explain that in a day or two) and from all the other activity this weekend. But it felt good to use my physique for its designed purpose. And it felt good to be tired because of physical exertion. I needed that. In more ways than one.

Back to top

One of those (working on a non-workday) days

Posted on August 16th, 2008 in Geek Stuff, Personal Messages, Rants | No Comments »

I really don’t like starting a Saturday working on work stuff at home. Especially when I am not supposed to be working on a Saturday. I don’t mind working when I am supposed to be working, but when I am supposed to be making breakfast for my family or taking care of stuff at home I get a little testy that I have to interrupt that so that I can tend to things at work.

So it went this morning, when by 8:45 I was getting called on my home phone and cell phone that there were things breaking left and right and why was this happening and what is going on? Huh?

It started with a frequent background job failing but not notifying. It then led to a series of other issues including an intranet that went down, an account management app that went down and our core site that went down. Coupled with that were all of the background jobs and middleware apps that were not transferring data as expected. Things were not working so me and a few fellow co-workers were.

The cause of the situation ended up being a few other nightly jobs running, killing something and never bringing those somethings back up. Then another job decided to reboot a server but not bring it back up properly. This in effect made all of the other servers that talk to the one that was reboot to stop talking to it. It happens. Anyone that has ever worked in an IT environment knows things like this happen.

But when handled properly it only happens the same way once. A second time means you didn’t learn from the first. Screwing up is inevitable and should be handled with grace and understanding the first time it happens. Any subsequent (and by that I mean the second time only… after that more than one person is to blame for these issues) instances of failure like this indicates an inability to learn from your own mistakes and should not, in my opinion, be handled with the same amount of grace and understanding as the first time. I know that may sound harsh, but that is the reality of living in a real-time environment in which money transacts and businesses serve.

The incident this morning was a case in point. Nothing that took place this morning should have taken place this morning. In fact, a remedy for this situation was put in place, for a different identical server, just a few days ago. So it begs the question, if an identical machine bought at the same time experienced something like this and was fixed, why would it’s twin not be fixed? You get my point.

What ended up happening is that three people, one of whom was me, ended up spending non-work time working because of an error on the part of another teammate of ours didn’t learn from the last time something like this happened. Yes, I am complaining about a teammate. We all are, or at least should be, held to the same level of accountability in everything we do as a unit. And this does not just hold true for work. It can easily be applied to sports, families, friendships and businesses.

I love my job. If I come across in a way that indicates anything otherwise please don’t hesitate to call me out on that. I actually look forward to coming into the office and taking care of business everyday with the team I work with. I appreciate their knowledge, their expertise and their experience. This is very much like my family, and more specifically my wife, whose experience and knowledge provides a wealth of protection to me and my family. My team at work provides a similar level of protection to our team at work.

That is the nature of a team environment. We protect us. We advance us. We are us. Every person on the team should take the responsibility for the success of the team and do whatever it takes to maintain a high level of accountability to the team to see to it that the team succeeds. If that is done then Saturdays can be spent as a normal Saturday and my blog post for today could have been about something entirely more pleasant than this.

Back to top

Loving me some PHP today

Posted on August 15th, 2008 in Geek Stuff, PHP, Programming, Web Development | No Comments »

Today I had the misfortune of having to migrate a website from one server to another for a sister company of ours. I say misfortune because this website is coded in the nastiest bit of Cold Fusion code I have ever seen. I mean it looked like a script kiddie that just learned how to regurgitate CFML from the back of a cereal box tutorial wrote it. And I had to make it work on a new server.

Did I mention that I haven’t been in Cold Fusion for over five years? And I hated it then.

Good thing that I am a fairly adept PHP developer. Instead of futzing with crappy CFML I decided to spend a few hours trying to port it to PHP in a sensible way with sensible coding and sensible architecture. The result was that I built a mini-MVC framework for it in about 4 hours. Aren’t I awesome? Well, isn’t PHP awesome?

I can do a lot of things in PHP typically in a short amount of time. I can write test snippets, mini-apps, middleware, all sorts of goodies fairly quickly when I need to with this language. And what I write generally is easily understood (comments anyone?) and easily maintained. I cannot say that about that pile of crap that was the Cold Fusion site. That stuff stunk like butts on a hog. But I shall try to not focus on that so much as tell you how much I love PHP today because it let me create a nifty little mock MVC style framework in about half a day.

Well, actually it is more of a VC framework with a small data handler object that talks to MySQL only. But it gets done what is necessary in an OOP style and is very easy to understand and maintain. Which is what I want.

Now all I have to do is port their templates and CSS over to something cleaner and I will be able to get their site off that vomitous mass of Cold Fusion Crap and on to something a lot prettier, easier to manage and, in my opinion, just plain better.

PS And if you are ever going to make a static HTML page for a single row of a database table, do not, anywhere in your code, set the row ID of the page information as it comes from the database as a hard coded numeric valued variable, then check if that variable is numeric, then pass that to the database as a query to get the page information of the page you are on. That is just stupid, plain and simple. Be smart, develop smart and use your brains. That is why we have them, to keep from making stupid mistakes that other, smarter, people might laugh at you for.

Back to top

Meeting up with some local MySQL users

Posted on August 14th, 2008 in Geek Stuff, Getting Out, MySQL | No Comments »

This past Monday I had the fortune of attending my very first meetup. I had set a goal for myself a few weeks ago that I would attend one before the end of the year. It happened way sooner that I thought it would and resulted in me being able to mix it up with a few fine folks at the Silicon Valley MySQL Meetup.

There was a business need for me hitting this thing up. Firstly, I am a web developer. I am not a DBA and I am certainly not a MySQL guru. I can write queries but the extent of my MySQL knowledge ends right about there. Secondly, I am responsible for management and maintenance of all of our MySQL servers at work. There is one chief DBA who is a Sybase queen, another two or three folks that know their way around a Sybase server (and to a lesser extent a general database server) and then there is me and my colleague who write web apps and MySQL queries. Thirdly, I am an administrator for a very popular PHP developers forum and knowing how to get myself out of the stupid ass scraped I have gotten us into when it comes to MySQL would be darn handy.

So I set out to hit this meetup. It was held at the Sun Microsystems complex in Palo Alto (or Redwood City or wherever you are when you come off the Dumbarton Bridge on the Peninsula side). I was looking forward to finally meeting a man that I have been communicating with for some time now (yes, you Don) and to networking with other MySQL/PHP/Web developers in my local geographic region. And I was not disappointed.

The talk itself was a little boring to be honest. But that is because I am not at all interested in database shards and the whatnot. However I was very interested in meeting Don Ravey, a fellow moderator on our forums, Mr. Tish Wood, a very prominent member of the PHP Meetup community and one of the coordinators of the meetup Eric Bergen from Proven Scaling. Not only that, but there were a host of other people there that provided excellent commentary, questions and challenges for the speaker of the evening.

I love being in the mixed company of brilliant people like that. It is humbling, exciting and gives me something to look forward to. I so enjoyed being there, connecting, talking with people, meeting a few folks and hopefully being able to glean something from someone somewhere. I just hope that I can, at some point, make it to another meetup. Perhaps a LAMP meetup or a PHP meetup. After this last meetup Tish asked me if I would at all be interested in speaking to a group at the Greater SF Bay Area LAMP meetup. I think I would love to do that.

If I can find an evening to get away for a while longer than this last evening. And if we can find a way to not have a meetup in San Francisco. Because as much as I like socializing and hanging with other technology professionals, I cannot fathom the thought of heading to The City for a 7:00 PM meeting on a weekday evening. Until then though, I can start thinking about what I would talk about if I were to ever talk.

And hopefully I will be a little more relevant to a n00B than that fella at the MySQL meetup was to me. He was good and he knew his stuff for the most part. But it was not my cup of tea so I sort of lost interest a little in the subject matter. That was ok though, because I met people, got numbers and had a free coke. In the end, what could be better than that?

Back to top

How to make sure your customers will hate you forever

Posted on August 13th, 2008 in Personal Messages, Rants, Web Services | 1 Comment »

This morning I was faced with an extraordinary issue when I got to work. We had no network services to our domain name. And apparently I was the one that was supposed to know why this was.

After looking closely at what was happening, and realizing that emails had not been received to our mail server for a time, and that none of our web sites were running, and that users of our VPN were calling complaining that they could not connect to the network for some reason it dawned on my that it was time to check our domain name servers.

A quick look as it was pretty apparent that our name servers zones were completely missing. After a little more time trying to figure out what was happening, and at the same time trying to vindicate myself from savage disciplinary action due to a recent domain name transfer request that has gone horribly awry, I finally came to the conclusion that our domain name provider (and our bandwidth provider) must have gone out of business last night. They have been on their last leg for quite some time and their services have tanked considerably. I figured this was the last leg of their journey into the toilet of despair.

I was wrong.

After following their horrible excuse of a menu system on their call-in support system I got to their new domain name providers (they have sold off every one of their divisions to other companies so I was actually talking to another company). At the same time I decided to call the guy that has been not helping transfer our corporate domain. While on hold with the new company I actually made contact with our current guy. And I found out something interesting: our zone files in their DNS server were removed because of failure to pay a bill.

Under normal circumstances I would say that this would make perfect sense from a business standpoint. Except for a few points:

  • The amount we owed was $225. Our normal monthly bill is about $2,500.
  • The last invoice they sent us was in May. For about $2,500.
  • The last invoice was for bandwidth and domain name management services.
  • Our DNS services were terminated because of an outstanding bandwidth invoice. Bandwidth remained online.
  • They never sent a bill for the outstanding amount.
  • They never attempted to contact us for the outstanding amount.
  • They have been providers of our for more than 10 years.
  • We are their biggest account.

That said I would say their handling of this case was an epic FAIL. Worse yet, the one guy that any answers for us (one of four remaining employees with the company) had no access to their systems, billing or otherwise, and was only able to add our zone files back. He was not able to transfer calls, take payments or offer any other insight into what was happening. He couldn’t even give us the phone number of their account person so we could contact her to straighten this out.

Once my director of IT was able to actually traverse their phone support system and get in touch with the woman that handles their billing and accounting it came to light that they never did send us an invoice and that we were apparently supposed to be mind readers when it came to paying for stuff we may or may not have used.

Ultimately the situation ended with my boss receiving confirmation that he would indeed receive an invoice that he could send to the AP department here so they could pay it and get us out of hock. And after a few minutes of downtime we were back on the air.

Now I know there are lessons to learn from all of this. But I think it would have been more useful and helpful if our service providers had taken to learning those lessons before shutting down a US$100M company for a stupid $225 invoice that was, get this, only 45 days late.

Wanna keep your customers happy? Try communicating with them. It would have made all the difference in this case.

Back to top

Being consumed by the 2008 Olympics

Posted on August 12th, 2008 in Rants | No Comments »

2008 Summer Olympics logoFew things carry with it the pageantry, showmanship and stigma of the Olympic Games. The best athletes in the world coming together in international competition on quite possibly the largest stage some of them will ever see. Media hounding everyone at every turn. Entire cities rebuilt to accommodate the athletes, fans, coaches, supporters and staff.

And coming around once every four years certainly helps the hype. If nothing more it certainly offers a unique excuse to children to stay up later than normal, jump off of things they would not usually be allowed to jump off of and shout at the TV like dad does on Sundays during the football season.

Strangely the one thing about the Olympics, the bringing together of families to enjoy something in the company of each other instead of being off Facebooking, MySpacing, Texting or something else, is the same thing that gives me the biggest issue of contention with the Olympics. My family has been consumed by these games.

Regardless of the sport, from swimming to gymnastics to beach volleyball, my wife can sit and watch the games all night. My kids have been staying up until midnight or later so they can watch the Olympics, which “only come around every four years”, with mom. And I think I have had my fill of it.

I like sport as much as the next guy, and I am all for the spirit of competition that the Olympics bring. But dude, I am on freaking Olympics overload. I am ready for the games to end already. I want my TV, my family and my nights back. Family TV night is great, but not when it starts at 9:00 PM and goes through 1:00AM the next morning and only includes mom and the two older girls.

And I think it would be better if even the non-mainstream sports made it on to TV. I would love to see some wrestling or shooting or table tennis. Not the most popular, certainly not the biggest named athletes in the world in these events, but still, the Olympics are more than just swimming, gymnastics and tack & field.

Still, I am enjoying what little of the games I am letting myself consume. They have been exciting and even breathtaking at times. But I have a feeling when these games are over I will be a little happier for their departure than their arrival.

Back to top

Trying to find the trust in people once again

Posted on August 11th, 2008 in Personal Messages, This Blog | 2 Comments »

A while back I turned comments off to unregistered users that were not logged in. What that did in effect was make it so that you had to not only register but also login in order to post comments on my blog.

I know that is a hassle but I was getting so much frickin spam that I had to do something. Akismet was doing nothing. I was moderating upward of 40 spams a day and I got tired of it.

But lately I have had a change of heart. I have ran across several very popular blogs that do not require user logins or even registration. And if those large scale blogs that are read by thousands of viewers a day can do that then my scant little blog can certainly do that, too.

So today I am restoring my trust in people. Trust that they will not abuse my little blog that all three of my loyal readers visits once every couple of weeks. Trust that spambots will not launch an all out attack against my little space on the internet. Trust that, if given the chance to say something about something that I have said, people might just speak up if it is easy enough for them to do so.

So I invite you to comment freely on my rants and blurbs. Beginning today.

Back to top

Catching up - Finally

Posted on August 10th, 2008 in General, This Blog | No Comments »

Man oh man has it been a long couple of weeks of blogging. I have so wanted to write so much. And if you are reading this now it means that I have finally caught up to this point on my blog. What that means is that three weeks of daily blogs have been added to my blog because I could not find the time to handle them as they happened.

My blog so needed love I could not give it. Glad it can’t divorce me because it would so have grounds.

Anyway, I am going to try to stay on top of things around here. Not saying I am going to. Just saying that I will try.

Back to top