<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Fliquid Studios</title>
	
	<link>http://www.fliquidstudios.com</link>
	<description>Beautiful Web Applications</description>
	<lastBuildDate>Fri, 03 Sep 2010 00:51:57 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/FliquidStudios" /><feedburner:info uri="fliquidstudios" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Never stop challenging yourself</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/yUxU9AOoT6Y/</link>
		<comments>http://www.fliquidstudios.com/2010/09/03/never-stop-challenging-yourself/#comments</comments>
		<pubDate>Fri, 03 Sep 2010 00:23:36 +0000</pubDate>
		<dc:creator>Christian Biggins</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[self improvement]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/2010/09/03/never-stop-challenging-yourself/</guid>
		<description><![CDATA[As a developer, its super easy to fall into a rythym and do the same things, the same way, forever. This doesn&#8217;t help make you a better developer, in fact, the least skilled and hardest developers to work with are generally the guys who are closed off to the prospect of &#8216;a better way&#8217;.
You don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p><script src="/SyntaxHighlighter/Scripts/shCore.js"></script><script src="/SyntaxHighlighter/Scripts/shBrushPhp.js"></script><script src="/SyntaxHighlighter/Scripts/shBrushXml.js"></script><script src="/SyntaxHighlighter/Scripts/shBrushSql.js"></script><script><!--
window.onload = function () {dp.SyntaxHighlighter.ClipboardSwf = '/flash/clipboard.swf';dp.SyntaxHighlighter.HighlightAll('code');}
// --></script>As a developer, its super easy to fall into a rythym and do the same things, the same way, forever. This doesn&#8217;t help make you a better developer, in fact, the least skilled and hardest developers to work with are generally the guys who are closed off to the prospect of &#8216;a better way&#8217;.</p>
<p style="text-align: left;">You don&#8217;t need to work in a team to challenge yourself on approaches to problems, design styles, methodologies or even small, tiny, one-line code changes. Of course, working around other developers who you respect makes a huge difference and can be extremely beneficial to not only your technical knowledge but your ability to stay open minded and accept that your answer is quite possibly not the best one for the current problem.</p>
<p>I think that a lot of developers who work solo, especially in their first few years of their career, can get caught in an &#8216;I know best&#8217; rut and are not willing or open to different points of view.</p>
<p>If you want to get better, you need to be challenged and that can be as mentally draining as a brain storming session, or as easy as writing a small script to test the differences between coding technicques or function calls.</p>
<p>Today, while working with my boss who I admire and respect for his technical prowess and general speed of uptake, I noticed that he takes a slightly different approach when using PHP variables in a MySQL INSERT query. In this particular scenario, there is a slight possibility that the variable will occasionally be an empty string which would cause syntax errors in the query. My boss wrapped the variable in an <a href="http://au.php.net/intval">intval()</a> call to default the value to 0 in case the string was empty. This was far different from my approach which would always to use a <a href="http://snippets.dzone.com/posts/show/76">shorthand if statement</a> to test the string and assign a value.</p>
<p>The intval() call in this scenario looks more elegant, but the shorthand statement is just something I have always done. I decided to put the two to the test by writing an unnecessary test on speed.</p>
<p>The first test used a shorthand statement with no function call;</p>
<pre name="code" class="php">
&lt;?php
$str = '';
$func_total = 0;
$sh_total = 0;

for ($i = 0; $i &lt;=1000; $i++) {

$func_start = microtime(true);
$val = intval($str);
$func_total += (microtime(true)-$func_start);

$sh_start = microtime(true);
$val = ($str? 0 : 1);
$sh_total += (microtime(true)-$sh_start);
}

print 'Function call total: ' . $func_total . PHP_EOL;
print 'Short hand total: ' . $sh_total . PHP_EOL;
</pre>
<blockquote><p>Function call total: 0.00370979309082<br />
Short hand total: 0.00205898284912</p></blockquote>
<p>Shorthand is quicker.</p>
<p>And, the second used an strlen() call;</p>
<pre name="code" class="html">&lt;?php
$str = '';
$func_total = 0;
$sh_total = 0;

for ($i = 0; $i &lt;=1000; $i++) {

$func_start = microtime(true);
$val = intval($str);
$func_total += (microtime(true)-$func_start);

$sh_start = microtime(true);
$val = (strlen($str) &gt; 0 ? 0 : 1);
$sh_total += (microtime(true)-$sh_start);
}

print 'Function call total: ' . $func_total . PHP_EOL;
print 'Short hand total: ' . $sh_total . PHP_EOL;
</pre>
<p>And was still quicker;</p>
<blockquote><p>Function call total: 0.00477647781372<br />
Short hand total: 0.00359439849854</p></blockquote>
<p>The test, as you can see, just simply executes the code 1000 times and records a total time elapsed for each one. Its silly, but was purely for my own curiosity. While the shorthand is faster, the intval() call is much nicer and I will likely opt to use it in future.</p>
<p>This is just one simple, quick method that challenges yourself and your methods for writing code. If you dont challenge yourself and let others challenge you, you have no hope of ever becoming a better developer.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/yUxU9AOoT6Y" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2010/09/03/never-stop-challenging-yourself/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2010/09/03/never-stop-challenging-yourself/</feedburner:origLink></item>
		<item>
		<title>Serving static content from Cloud Files using Ruby</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/fnLbGEKPu-M/</link>
		<comments>http://www.fliquidstudios.com/2010/03/29/serving-static-content-from-cloud-files-using-ruby/#comments</comments>
		<pubDate>Mon, 29 Mar 2010 10:57:15 +0000</pubDate>
		<dc:creator>Christian Biggins</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Reference]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/2010/03/29/serving-static-content-from-cloud-files-using-ruby/</guid>
		<description><![CDATA[I recently moved my site <a href="http://skylinesaustralia.com">skylinesaustralia.com</a> from hosting in the states back to hosting in Australia and while it is reasonably affordable, one thing I can't afford is a burst in bandwidth. I average 600GB outbound per month and I only have 600GB allowance with my server, so I decided to serve my gallery and post attachment images from Rackspaces <a href="http://www.rackspacecloud.com/cloud_hosting_products/files">Cloud Files</a> service. The Cloud Files service is much like Amazons S3 service, only faster and for a similar amount of money.]]></description>
			<content:encoded><![CDATA[<p><script src="/SyntaxHighlighter/Scripts/shCore.js"></script><script src="/SyntaxHighlighter/Scripts/shBrushRuby.js"><script src="/SyntaxHighlighter/Scripts/shBrushPhp.js"></script><script type="text/javascript">// <![CDATA[
 window.onload = function () {dp.SyntaxHighlighter.ClipboardSwf = '/flash/clipboard.swf';dp.SyntaxHighlighter.HighlightAll('code');}
// ]]&gt;</script>I recently moved my site <a href="http://skylinesaustralia.com">skylinesaustralia.com</a> from hosting in the states back to hosting in Australia and while it is reasonably affordable, one thing I can't afford is a burst in bandwidth. I average 600GB outbound per month and I only have 600GB allowance with my server, so I decided to serve my gallery and post attachment images from Rackspaces <a href="http://www.rackspacecloud.com/cloud_hosting_products/files">Cloud Files</a> service. The Cloud Files service is much like Amazons S3 service, only faster and for a similar amount of money.</p>
<p>My issue with this was that my gallery on SAU is 100GB in size, so using something to mount the Cloud Files 'container' locally using fuse or something similar is far too slow and without mounting it, I cannot use rsync. Even if I did manage to mount it, I had no way of doing an 'immediate' sync when files were uploaded.</p>
<p>After some thinking and chatting with a very cluey sys admin at work, I looked at <a href="http://inotify.aiken.cz/">inotify</a>. Basically, inotify (and <a href="http://wiki.github.com/rvoicilas/inotify-tools">inotify-tools</a>) alerts you of changes to files and directories, thus making it possible to write scripts based on changes to the file system. Awesome!</p>
<p>Rackspace provides a bunch of very nice API interfaces for all sorts of languages. I used <a href="http://github.com/rackspace/ruby-cloudfiles">Ruby</a>, but the <a href="http://github.com/rackspace/php-cloudfiless">PHP</a> one is also great.</p>
<p>So, my approach was to monitor a directory for changes, capture the changes, use the file name and location captured and push the changes via the Cloud Files API. Then, we can view the files using the Cloud Files CDN URL. This is easily the trickiest to get right, but the easiest to set up and requires very little integration to work for any site.</p>
<p>The first thing I did was write a little Ruby script to upload files to a container on Cloud Files. I wanted this script to remain generic so that I could use it to push my database backups to Cloud Files also.</p>
<pre name="code" class="ruby">
require 'rubygems'
require 'cloudfiles'

# Log into the Cloud Files system
cf = CloudFiles::Connection.new("username", "APIKey")

if ARGV.empty? then
    print "Usage: \n"
    print "pushToCloud.rb &lt;container&gt; &lt;remotefile&gt; &lt;localfile&gt; \n"
    print "remote file MUST contain relative path under the container!\n"
else
    container = cf.container(ARGV[0])
    if container.object_exists?(ARGV[1]) then
        # object (file) exists
    else
        # object does not exist...
        newfile = container.create_object(ARGV[1], true)
        newfile.load_from_filename(ARGV[2])
    end
end
</pre>
<p>This is very simple. Connects to Cloud Files, checks if the object (file) exists, if not, it creates a new object and writes data to it. There are a few things to note here;</p>
<ol>
<li>An 'object' is the name of anything in Cloud Files; a file or a directory can be an 'object'</li>
<li>Objects don't have a path, they are named with their path. ie /var/log/my.log gets sent as '/var/log/my.log' - the path is part of the name. (At least this is how I understand it)</li>
<li>Objects can be created but not written to. This concept means that you need to create and object and then write data to it (you can see this in the code above.)</li>
</ol>
<p>Now that I have my Ruby script, I will write a small bash script;</p>
<pre name="code" class="php">
#!/bin/sh
function checkExists {
    if [ ! -e "$1" ]
    then
        sleep 5
        checkExists $1
    fi
}

inotifywait -mr --timefmt '%d/%m/%y-%H:%M' --format '%T %w %f' -e modify,moved_to,create,delete /home/skylines/html/forums/uploads | while read date dir file; do

    cloudpath=${dir:20}${file}
    # I only want everything after /home/skylines/html/
    localpath=${dir}${file}
    checkExists $localpath
    ruby /home/cbiggins/bin/pushToCloud.rb skylinesaustralia.com $cloudpath $localpath
    echo "${date} ruby /home/cbiggins/bin/pushToCloud.rb skylinesaustralia.com $cloudpath $localpath" &gt;&gt; /var/log/pushToCloud.log
done
</pre>
<p>So, this very simple script uses <a href="http://linux.die.net/man/1/inotifywait">inotifywait</a> to monitor my uploads directory for changes (modify, moved_to, create and delete changes) and writes the path and file to stdout, then my while loop grabs that output and reads it into the date, directory and file. We create a few paths for Cloud Files and locally and we pass them to my Ruby script. I am also a big advocate of logging everything, so I write my changes to a log file also. Note the checkExists function - if this bash script gets called before the file has completed uploading, then its not available to be pushed to Cloud FIles and we end up with errors, so this function just sleeps for 5 seconds if its not there and trys again until the file exists.</p>
<p>As you can see, pushing files to the 'Cloud' is extremely easy and apps like inotify and inotify-tools make it super simple to monitor and perform actions based on file system changes.</p>
<p>If you have any suggestions or questions, please don't hesitate to leave a comment below.</p>
<p>Thanks!</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/fnLbGEKPu-M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2010/03/29/serving-static-content-from-cloud-files-using-ruby/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2010/03/29/serving-static-content-from-cloud-files-using-ruby/</feedburner:origLink></item>
		<item>
		<title>Dont get caught by differing super globals in PHP</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/ehYXKUOPOnw/</link>
		<comments>http://www.fliquidstudios.com/2010/01/25/dont-get-caught-by-differing-super-globals-in-php/#comments</comments>
		<pubDate>Mon, 25 Jan 2010 04:38:55 +0000</pubDate>
		<dc:creator>Christian Biggins</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Fedora]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[quality]]></category>
		<category><![CDATA[Reference]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/2010/01/25/dont-get-caught-by-differing-super-globals-in-php/</guid>
		<description><![CDATA[Recently I discovered that scripts I had written on my Mac would not run on our Linux servers. It wasn't until I had a good look at the contents of the $_SERVER super global that I noticed a few anomalies with the contents of mine compared with others that I have been used to for so long...]]></description>
			<content:encoded><![CDATA[<p><script src="/SyntaxHighlighter/Scripts/shCore.js"></script><script src="/SyntaxHighlighter/Scripts/shBrushPhp.js"></script><script type="text/javascript">// <![CDATA[
window.onload = function () {dp.SyntaxHighlighter.ClipboardSwf = '/flash/clipboard.swf';dp.SyntaxHighlighter.HighlightAll('code');}// ]]&gt;</script>
<p>Recently I discovered that scripts I had written on my Mac would not run on our Linux servers. It wasn&#8217;t until I had a good look at the contents of the $_SERVER super global that I noticed a few anomalies with the contents of mine compared with others that I have been used to for so long&#8230;</p>
<p>Here is the main difference between mine and Mikes $_SERVER super global.</p>
<p>PHP 5.2.9 on Fedora 10 (Mikes dev machine)<br />
["REQUEST_URI"]=&gt; string(9) &#8220;/test.php&#8221;</p>
<p>PHP 5.3.0 on Mac OS X (10.6)<br />
["REQUEST_URI"]=&gt; string(28) &#8220;http://fliquid.dev/blog.html&#8221;</p>
<p>As you can see, the changes are sufficient to cause a lot of problems to a lot of scripts. Writing a regex to match either your REQUEST_URI (in this example) would fail on a script I write when it goes live and also any script that Mike writes that I run.</p>
<p>To get around this, we will likely write a small &#8216;compat&#8217; (compatibility) library for detecting which style of super global is being used and append specific changes to each one so we only need to write one version of the code.</p>
<p>This is just a little &#8216;heads up&#8217; to reduce the amount of hair pulling that can occur when scripts are pushed to a nix production environment after being developed on a Mac.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/ehYXKUOPOnw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2010/01/25/dont-get-caught-by-differing-super-globals-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2010/01/25/dont-get-caught-by-differing-super-globals-in-php/</feedburner:origLink></item>
		<item>
		<title>Making sure you only have one instance of a script running</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/Dee8VDZlfqw/</link>
		<comments>http://www.fliquidstudios.com/2010/01/20/making-sure-you-only-have-one-instance-of-a-script-running/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 23:58:24 +0000</pubDate>
		<dc:creator>Christian Biggins</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[Library]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Reference]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/2010/01/20/making-sure-you-only-have-one-instance-of-a-script-running/</guid>
		<description><![CDATA[// 
One of my tasks in my current job is to build large indexes for our Sphinx powered search engine. This sounds pretty simple, but when you have 2,000,000 records that have, in turn, one-to-many relationships with other records, you can be processing a huge amount of data at any given time.
The script that I [...]]]></description>
			<content:encoded><![CDATA[<p><script src="/SyntaxHighlighter/Scripts/shCore.js"></script><script src="/SyntaxHighlighter/Scripts/shBrushPhp.js"></script><script type="text/javascript">// <![CDATA[
window.onload = function () {dp.SyntaxHighlighter.ClipboardSwf = '/flash/clipboard.swf';dp.SyntaxHighlighter.HighlightAll('code');}// ]]&gt;</script></p>
<p>One of my tasks in my current job is to build large indexes for our Sphinx powered search engine. This sounds pretty simple, but when you have 2,000,000 records that have, in turn, one-to-many relationships with other records, you can be processing a huge amount of data at any given time.</p>
<p>The script that I wrote to gather the data in preparation for indexing was a little heavy on the memory side of things and it was a huge problem when that script had not completed in time for the next cron job, which would evidently start a giant snowball as for every instance of the script, it ran slower, so there would be no end in sight and we&#8217;d have to manually kill all the processes. Thats not a great solution for many reasons, but when data integrity is of the utmost importance, you can&#8217;t just go killing your scripts willy nilly.</p>
<p>I found a great little class written by <a href="http://The%20VPS%20servers%20are%20provisioned%20with%20a%20base%20CentOS%20installation.%20You%20have%20full%20root%20access%20to%20install%20any%20modules%20and%20perform%20any%20customisation%20that%20you%20may%20require.">Chris Hope at electrictoolbox.com</a> that touches a file and writes the scripts Process ID (PID) to the file so any other instances can check that file to see if their own PID is in there, if its not their PID, they die. Otherwise, they can continue. Also, if the file exists, but the PID inside the file is not valid anymore (ie the script was killed and had no opportunity to remove the file) the new instance can still run. Its a two-stage check.</p>
<p>I have made a few small adaptations to the original class and my version is here;</p>
<pre name="code" class="php">&lt;?php
    class pid
    {
        protected $filename;
        public $already_running = false;

        function __construct($directory)
        {
            $this->filename = $directory . '/' . basename($_SERVER['PHP_SELF']) . '.pid';
            if(is_writable($this->filename) || is_writable($directory)) {
                if(file_exists($this->filename)) {
                    $pid = (int)trim(file_get_contents($this->filename));
                    if(file_exists('/proc/' . $pid)) {
                        $this->already_running = true;
                    }
                }
            } else {
                die("Cannot write to pid file '$this->filename'. Program execution halted.\n");
            }

            if(!$this->already_running) {
                $pid = getmypid();
                file_put_contents($this->filename, $pid);
            }
        }

        public function kill()
        {
            // Make sure this script owns the file before we delete it...
            $pid = (int)trim(file_get_contents($this->filename));
            if(file_exists('/proc/' . $pid) &#038;&#038; $pid == getmypid()) {
                unlink($this->filename);
            }
        }
    }
</pre>
<p>Can can be used like so;</p>
<pre name="code" class="php">&lt;?php
    class newclass
    {
        public function __construct()
        {
            if ($this->checkPid()) {
                // Continue...
                $this->killPid();
            }
        }

        private function killPid()
        {
            $this->pid->kill();
        }

        private function checkPid()
        {
            $this->pid = new pid('/tmp');
            if ($this->pid->already_running) {
                print 'Already running. Exiting.' . PHP_EOL;
                exit;
            } else {
                return true;
            }
        }
    }
</pre>
<p>The main difference is that I don&#8217;t use __destruct() as I wanted to be able to call a kill() method. The other notable difference is that my version does not use posix_kill() and instead checks that the process file in /proc exists. Keep in mind that this <b>will not work</b> on Windows or Mac operating systems as the /proc directory is unique to Linux. The reason I made this change is that posix_kill requires a PHP extension.</p>
<p>Thanks to Chris Hope for the original class.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/Dee8VDZlfqw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2010/01/20/making-sure-you-only-have-one-instance-of-a-script-running/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2010/01/20/making-sure-you-only-have-one-instance-of-a-script-running/</feedburner:origLink></item>
		<item>
		<title>Sphinx Full Text Search, What I have learned</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/RE9W-QyEC-g/</link>
		<comments>http://www.fliquidstudios.com/2009/11/30/sphinx-full-text-search-what-i-have-learned/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 03:12:45 +0000</pubDate>
		<dc:creator>Christian Biggins</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[How To]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[projects]]></category>
		<category><![CDATA[Reference]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[Sphinx]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/2009/11/30/sphinx-full-text-search-what-i-have-learned/</guid>
		<description><![CDATA[For those of you that do not know what Sphinx is, check out their site here.


  

I started writing a post on Sphinx a few weeks ago, only to realise that the way I was approaching Sphinx was wrong and that I had to rethink my strategy. Anybody that follows my personal blog will [...]]]></description>
			<content:encoded><![CDATA[<p>For those of you that do not know what Sphinx is, check out <a href="http://sphinxsearch.com" title="Sphinx">their site here</a>.</p>
<p></p>
<div style="text-align: center;">
  <img src="http://www.fliquidstudios.com/wp-content/uploads/2009/11/284743_2835.jpg" width="199" height="149" alt="284743_2835.jpg" />
</div>
<p>I started writing a post on Sphinx a few weeks ago, only to realise that the way I was approaching Sphinx was wrong and that I had to rethink my strategy. Anybody that follows <a href="http://www.christianbiggins.com" title="Christian Biggins Dot Com">my personal blog</a> will see that I had to rewrite my Sphinx implementation several times because of my approach to the problem.</p>
<p>Let me just say that I was initially attracted to Sphinx a few years ago, when my site Skylines Australia kept hitting table-locks due to MyISAM. We needed MyISAM for Full Text searches, or at least we did, until we discovered Sphinx. Once our indexes were built, we were searching very quickly across 4.5 million posts with far less overhead than MySQL. It also meant we could change our table engine to InnoDB so we could get around the table-level-locks.</p>
<p>The issue is, that we have a lot of data here at work and we have lots of search inputs. Think &#8216;keyword&#8217; and &#8216;category&#8217; in &#8216;location&#8217;; We initially approached it like so;</p>
<ol>
<li>Search the location index, get a location id</li>
<li>Search the Category index, get a category id</li>
<li>Search the Main index using the location id and category id as filters.</li>
</ol>
<p>Now, thats ok, but what if you have hierarchical categories and locations? Ie, Searching for &#8216;Mechanics&#8217; needs to include &#8216;Motor Mechanics,&#8217; &#8216;Bike Mechanics,&#8217; &#8216;Boat Mechanics&#8217; etc&#8230; We had one search that needed to search across 1800 categories! The other issue we ran into is we needed to have proximity searches. If there were less than <i>n</i> results at the Suburb Level, we would expand to the Area, then the Region, all the way to the State. This meant that we would need to run the searches 4 times (or 12 in total) so we could keep our results separate. Couple this with 1.9 million searchable rows, 25,000 locations and 2000 categories, searches were taking a __LONG__ time to complete with Sphinx.</p>
<p>So.. Back to the drawing board.</p>
<p>My boss mentioned that Sphinx is built to search documents and that maybe we need to make a &#8216;document&#8217; structure for each of our records. I was a little dubious at first.. Here is the idea;</p>
<p>As Sphinx searches for matches and does not actually return the data it has found (only the data&#8217;s &#8220;document id&#8221; so you can query MySQL for the exact match) it means that our data in Sphinx does not need to be readable to humans, it can be a mashup of multiple data sources.</p>
<ol>
<li>We get all the items we want searchable and all their keywords, put them into a single column named &#8216;document&#8217; and create a new table in MySQL.</li>
<li>We get all the categories that this item must appear in, so not exact categories (like &#8216;Motor Mechanics&#8217;) but all the parents also, so we have fewer search terms, we get the category id&#8217;s and prefix them with &#8216;cat_&#8217;.</li>
<li>We create a new column called &#8216;location&#8217; and in that column, we get the id&#8217;s for the location the item is in, we prefix each &#8216;part&#8217; of the location with its &#8216;type&#8217;, ie &#8217;suburb_&#8217;, &#8216;area_&#8217;, &#8216;region_&#8217;, &#8217;state_&#8217;, etc.</li>
</ol>
<p>Once we are done, we have a row that looks like this;<br />
Id: Actual id of the item row (relating to its original table)<br />
Document: &#8216;Jims Mechanics quality mechanics we do good work cat_199 cat_432 cat_909 cat_2 cat_93&#8242;<br />
Location: &#8216;Manly Sydney NSW Australia suburb_1022 area_300 region_23 state_3&#8242;</p>
<p>Once we build this table and index it, we can query the index using the <a href="http://pecl.php.net/package/sphinx" title="PECL Sphinx">PECL Sphinx library</a> (much better than the supplied Sphinx PHP API) and Sphinx&#8217;s &#8216;EXTENDED2&#8242; query type like so;<br />
&#8216;@document $keywords @document (cat_1|cat_2|cat_3) @location suburb_1&#8242;<br />
AND is implied with Sphinx, so the above query is saying match the keywords, any of the 3 categories AND location. More about the cool EXTENDED2 query syntax can be found in the <a href="http://www.sphinxsearch.com/docs/manual-0.9.9.html#extended-syntax">Sphinx Docs</a>.</p>
<p>Basically, because we restructured our data to match Sphinx and didn&#8217;t try to make Sphinx work the way it wasn&#8217;t designed to, we saved lots and lots of queries, made it perform hundreds of times better (think thousandth&#8217;s of seconds to perform a search) and have alleviated MySQL of a lot of potentially damaging work. If you do anything with Full Text or require indexes for anything at all, I&#8217;d highly recommend Sphinx. It may seem a little odd at first and hard to get to do something, but persevere and try to rethink your situation, it will be worth it in the end.</p>
<p style="text-align: center;"><img src="http://www.fliquidstudios.com/wp-content/uploads/2009/11/1078636_89870249.jpg" width="174" height="130" alt="1078636_89870249.jpg" /></p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/RE9W-QyEC-g" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2009/11/30/sphinx-full-text-search-what-i-have-learned/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2009/11/30/sphinx-full-text-search-what-i-have-learned/</feedburner:origLink></item>
		<item>
		<title>Setting up a Facebook style link preview image</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/JXX3KzdajL8/</link>
		<comments>http://www.fliquidstudios.com/2009/09/09/setting-up-a-facebook-style-link-preview-image/#comments</comments>
		<pubDate>Tue, 08 Sep 2009 22:49:23 +0000</pubDate>
		<dc:creator>Michael Little</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[file_get_contents]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[preg_match_all]]></category>
		<category><![CDATA[regular expression]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/?p=316</guid>
		<description><![CDATA[Have you ever noticed in facebook when you add a link that it generates a list of images from that link so you can choose one to display? It can really help to give an idea of what the link is about and helps to brighten things up by adding some colour.
I&#8217;ve recently implemented similar [...]]]></description>
			<content:encoded><![CDATA[<p>Have you ever noticed in facebook when you add a link that it generates a list of images from that link so you can choose one to display? It can really help to give an idea of what the link is about and helps to brighten things up by adding some colour.</p>
<p>I&#8217;ve recently implemented similar functionality on one of my sites so I thought I&#8217;d share some of it. The whole process is quite long and involved and you may want to do things differently depending on your needs so in this article we will just be focussing on the initial steps to build an array of image URLs in PHP. The idea behind this functionality is really very simple: Look at a page and extract all of the images matching a certain criteria &#8211; in this case we&#8217;ll look for any images larger (or equal to) in width and height than the thumbnail we want to display.</p>
<p><strong>So let&#8217;s get started&#8230;</strong></p>
<pre><code>
&lt;?php

$link = 'http://www.martialartslife.net';
$width = 120;
$height = 90;
$regex = '/&lt;img[^\/]+src="([^"]+\.(jpe?g|gif|png))/';

</code></pre>
<p>Basically in the lines above we&#8217;re setting up a few variables. The $link variable could really come from anywhere, it is the link that we&#8217;re going to pull images from. $width and $height are the minimum size of the images we&#8217;ll use &#8211; This can be set to whatever size you like depending on the thumbnail size you need. Lastly, we&#8217;re defining a regular expression that will be used to locate the src attribute of image tags. We&#8217;re looking for any img tag that has a JPG, GIF or PNG.</p>
<p><strong>Next:</strong></p>
<pre><code>
function rel2abs($url, $host) {
    if (substr($url, 0, 4) == 'http') {
        return $url;
    } else {
        $hparts = explode('/', $host);

        if ($url[0] == '/') {
            return implode('/', array_slice($hparts, 0, 3)) . $url;
        } else if ($url[0] != '.') {
            array_pop($hparts);
            return implode('/', $hparts) . '/' . $url;
        }
    }
}

</code></pre>
<p>Here we are defining a function named rel2abs that is intended to convert a relative image src attribute (or any URL) into an absolute URL using a $host variable that is passed to it. We will use the original $link variable for this purpose. The function used here is very simplistic to keep the code short. It may not catch all possible cases. I would recommend expanding on this function a bit to make it more comprehensive before using it.</p>
<p><strong>Lastly:</strong></p>
<pre><code>
if (($data = file_get_contents($link)) &amp;&amp; preg_match_all($regex, $data, $m, PREG_PATTERN_ORDER)) {
    if (isset($m[1]) &amp;&amp; is_array($m[1])) {
        $thumbs = array();
        foreach (array_unique($m[1]) as $url) {
            if (
                ($url = rel2abs($url, $link)) &amp;&amp;
                ($i = getimagesize($url)) &amp;&amp;
                $i[0] &gt;= ($width-10) &amp;&amp;
                $i[1] &gt;= ($height-10)
            ) {
                $thumbs[] = $url;
            }
        }
    }

    print_r($thumbs);
}

</code></pre>
<p>This is the code that does all the work. The PHP function file_get_contents is used to retrieve the HTML content of the link, preg_match_all is then used with the previously defined regular expression to find all the images. Once all the images are found we then loop over them to determine if they match our size requirements and if so, we add them into the $thumbs array.</p>
<p>What you&#8217;re left with at the end of this code is an array of absolute URLs pointing to images that were on the link page. From here it is up to you what you do with the images. It might be that you want to display them for the user to choose one somehow or perhaps you&#8217;ve got something else in mind&#8230;.</p>
<p>That&#8217;s all for now.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/JXX3KzdajL8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2009/09/09/setting-up-a-facebook-style-link-preview-image/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2009/09/09/setting-up-a-facebook-style-link-preview-image/</feedburner:origLink></item>
		<item>
		<title>Milk framework example – martialartslife.net</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/rmwD7CwkhWY/</link>
		<comments>http://www.fliquidstudios.com/2009/07/02/milk-framework-example-martialartslifenet/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 03:36:26 +0000</pubDate>
		<dc:creator>Michael Little</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[milk]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/?p=307</guid>
		<description><![CDATA[Yesterday the first fully functional site using the new Fliquid Studios Milk framework was lanched, www.martialartslife.net. This site is quite basic as far as the capabilities of the framework go and will no doubt implement some of the more advances features further down the track.
Some of the base features it does make good use of [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday the first fully functional site using the new Fliquid Studios Milk framework was lanched, <a title="www.martialartslife.net" href="http://www.martialartslife.net" target="_blank">www.martialartslife.net</a>. This site is quite basic as far as the capabilities of the framework go and will no doubt implement some of the more advances features further down the track.</p>
<p>Some of the base features it does make good use of include:</p>
<ul>
<li>A large number of base controls including form controls, layout controls etc.</li>
<li>Automatic Javascript &amp; CSS concatenation and compression.</li>
<li>Good caching capabilities</li>
<li>CSS Sprite capabilities</li>
<li>Themes for controls</li>
</ul>
<p>The site was developed relatively quickly on along with the actual development of the framework. Many new features were added over the last couple of weeks before the launch which is a testiment to the ease of development provided by Milk.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/rmwD7CwkhWY" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2009/07/02/milk-framework-example-martialartslifenet/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2009/07/02/milk-framework-example-martialartslifenet/</feedburner:origLink></item>
		<item>
		<title>Creating a virtual development server using Virtualbox</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/iUYSngKqV0M/</link>
		<comments>http://www.fliquidstudios.com/2009/06/18/creating-a-virtual-development-server-using-virtualbox/#comments</comments>
		<pubDate>Thu, 18 Jun 2009 04:42:09 +0000</pubDate>
		<dc:creator>Christian Biggins</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[Fedora]]></category>
		<category><![CDATA[Integration]]></category>
		<category><![CDATA[SSH]]></category>
		<category><![CDATA[Virtualisation]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/2009/06/18/creating-a-virtual-development-server-using-virtualbox/</guid>
		<description><![CDATA[For those of you who read Installing Fedora 10 on Windows XP using VirtualBox, this is another post along the same lines as that one, except this one is for configuring your virtual machine as a development server for when you are forced to code on your Windows host.

I am a bit of a snob [...]]]></description>
			<content:encoded><![CDATA[<p>For those of you who read <a href="http://www.fliquidstudios.com/2009/03/19/installing-fedora-10-on-windows-xp-using-virtualbox/">Installing Fedora 10 on Windows XP using VirtualBox</a>, this is another post along the same lines as that one, except this one is for configuring your virtual machine as a development server for when you are forced to code on your Windows host.</p>
<p><a href="http://www.fliquidstudios.com/wp-content/uploads/2009/06/f10-in-vb.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="f10_in_vb" border="0" alt="f10_in_vb" src="http://www.fliquidstudios.com/wp-content/uploads/2009/06/f10-in-vb-thumb.png" width="244" height="169" /></a></p>
<p>I am a bit of a snob when it comes to development, I simply refuse to develop on a windows host as I just think that the app will end up being deployed on a nix system, so it should be developed on a nix system. I also think using a windows host for development takes away from a lot of the raw development involved with using nix systems. And, with the amount of quality development and virtualization tools available to us these days, we can develop on anything, using any tool.</p>
<p>If you haven’t set up a virtual machine using Virtualbox and your choice of Linux OS on a Windows machine, then read through <a href="http://www.fliquidstudios.com/2009/03/19/installing-fedora-10-on-windows-xp-using-virtualbox/">my other post</a> before continuing with this one. Also note, you will need to have Apache configured and running on your virtual machine.</p>
<p>Now, what I am going to do is configure VirtualBox to accept connections to itself on port 80 and port 22, so we can develop on one machine (Windows) but using a Linux server.</p>
<h2>Configure the network</h2>
<p>The first thing we need to do is get our machine on our local network and a proper IP address for it. Open up the settings for your virtual machine and click on the ‘network’ tab, then select ‘Adapter 2’ and change ‘Attached To’ to ‘Host Interface’. This will allow your virtual machine to get a DHCP assigned IP address and actually put it on the network.</p>
<p><a href="http://www.fliquidstudios.com/wp-content/uploads/2009/06/vm-network.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="vm_network" border="0" alt="vm_network" src="http://www.fliquidstudios.com/wp-content/uploads/2009/06/vm-network-thumb.png" width="244" height="219" /></a></p>
<p>Save your changes and boot your VM.</p>
<p><strong>Note: </strong>In later versions of VirtualBox (ie, 2.2.4) your Network adapter screen may look like the following, in which case just copy the settings I have used here.</p>
<p><a href="http://www.fliquidstudios.com/wp-content/uploads/2009/07/20090714-1137.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Alternate VM Network" border="0" alt="Alternate VM Network" src="http://www.fliquidstudios.com/wp-content/uploads/2009/07/20090714-1137-thumb.png" width="244" height="185" /></a> </p>
<p><strong>Configuring Apache / Port 80</strong></p>
<p>Now we need to make sure our Guest Linux OS can accept connections on port 80. Fedora 10 blocks these connections by default, to open them, edit the file /etc/sysconfig/iptables using vim, emacs, gedit, pico, whatever. Find the line accepting port 22 connections that looks like this;</p>
<blockquote><p>-A INPUT -m state &#8211;state NEW -m tcp -p tcp &#8211;dport 22 -j ACCEPT</p>
</blockquote>
<p><em></em>And add a line below it like this;</p>
<blockquote><p>-A INPUT -m state &#8211;state NEW -m tcp -p tcp &#8211;dport 80 -j ACCEPT</p>
</blockquote>
<p>Now restart iptables;</p>
<blockquote><p><span style="background-color: #ffffff; font-family: verdana">$ service iptables restart</span></p>
</blockquote>
<h2>Forwarding port 80</h2>
<p>The next step is to forward your port 80 to your virtual machine. You can forward any port you like, for example, you might have a web server on your Host machine and not want to forward port 80, so you can choose port 8080. I want a seamless virtual server environment, so I chose port 80.</p>
<p>Open up a command prompt (Start &gt; Run &gt; ‘cmd’ + Enter) and change to your Virtual Box directory;</p>
<blockquote><p>cd C:\Program Files\Sun\xVM VirtualBox</p>
</blockquote>
<p>Now we will get aquainted with the command line tool, ‘VBoxManage.exe’.</p>
<p>To forward port 80 on your host to port 80 on your guest, type the following (make sure you substitute “Fedora 10” with your VM’s name);   <br /><strong>NOTE:</strong> <a href="http://www.fliquidstudios.com/2009/06/18/creating-a-virtual-development-server-using-virtualbox/comment-page-1/#comment-23476" target="_self">Leo in the comments</a> has recommended changing &#8216;pcnet&#8217; to &#8216;e1000&#8242; for Intel network cards!</p>
<blockquote><p>VBoxManage.exe setextradata &quot;Fedora 10&quot; VBoxInternal/Devices/pcnet/0/LUN#0/Config/Apache/HostPort 80</p>
<p>VBoxManage.exe setextradata &quot;Fedora 10&quot; VBoxInternal/Devices/pcnet/0/LUN#0/Config/Apache/GuestPort 80</p>
<p>VBoxManage.exe setextradata &quot;Fedora 10&quot; VBoxInternal/Devices/pcnet/0/LUN#0/Config/Apache/Protocol TCP</p>
</blockquote>
<p>Then we can view our changes using the following command;</p>
<blockquote><p>VBoxManage.exe getextradata &quot;Fedora 10&quot; enumerate</p>
</blockquote>
<p><a href="http://www.fliquidstudios.com/wp-content/uploads/2009/06/vbmoxmana-port80.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="vbmoxmana_port80" border="0" alt="vbmoxmana_port80" src="http://www.fliquidstudios.com/wp-content/uploads/2009/06/vbmoxmana-port80-thumb.png" width="244" height="73" /></a></p>
<h2>Browsing to your virtual server</h2>
<p>At this stage you should be able to browse to your virtual server using any of the name based or home based virtual hosts on your vm.   <br />ie, browsing to localhost on your host machine should display the default virtual host on your guest.</p>
<p>However, if you have name based virtual hosts on your guest (as I do) then you need to add those names to your windows ‘hosts’ file so it knows to look for them locally and not on the internet. This is very easy to do.</p>
<p>Open the file c:\Windows\System32\drivers\etc\hosts and add the names of all your name based hosts after ‘localhost’ on the line starting with 127.0.0.1, eg;</p>
<blockquote><p><span style="background-color: #ffffff; font-family: verdana">127.0.0.1&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; localhost host1 host2 mysite</span></p>
</blockquote>
<p>Then, after saving, these hosts on your guest should load in your browser from the guest machine.</p>
<h2>Setup ssh server</h2>
<p>If you want to edit the files on your guest from your host using SFTP through an IDE (like <a href="http://www.netbeans.org/" target="_blank">Netbeans</a>, <a href="http://www.zend.com/en/products/studio/" target="_blank">Zend Studio</a>, <a href="http://eclipse.org/" target="_blank">Eclipse</a>) or an app like <a href="http://winscp.net/eng/index.php" target="_blank">WinSCP</a>, then keep reading.</p>
<p>Having an SFTP connection to a server is a great way to integrate your remote files into your local development environment and makes editing much easier and faster. SFTP is FTP over SSH and requires only an SSH connection to the server to work. We need to make sure ssh is running on our Guest;</p>
<blockquote><p><span style="background-color: #ffffff; font-family: verdana">$ service sshd start</span></p>
</blockquote>
<p>Now, we want to make sure it starts when the machine starts;</p>
<blockquote><p><span style="background-color: #ffffff; font-family: verdana">chkconfig sshd on</span></p>
</blockquote>
<p>We now need to follow the same procedure to forward the host port 22 to the guest port 22 as we did for port 80 above;   <br /><strong>NOTE:</strong> <a href="http://www.fliquidstudios.com/2009/06/18/creating-a-virtual-development-server-using-virtualbox/comment-page-1/#comment-23476" target="_self">Leo in the comments</a> has recommended changing &#8216;pcnet&#8217; to &#8216;e1000&#8242; for Intel network cards!</p>
<blockquote><p>VBoxManage.exe setextradata &quot;Fedora 10&quot; VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/HostPort 22</p>
<p>VBoxManage.exe setextradata &quot;Fedora 10&quot; VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/GuestPort 22</p>
<p>VBoxManage.exe setextradata &quot;Fedora 10&quot; VBoxInternal/Devices/pcnet/0/LUN#0/Config/ssh/Protocol TCP</p>
</blockquote>
<p>Now you will be able to ssh to the guest from your host. You can test this in <a href="http://chiark.greenend.org.uk/~sgtatham/putty/" target="_blank">putty</a> (or anything you’d like) by connecting to 127.0.0.1 on port 22 and logging into your guest machine with your normal user details.</p>
<p>Thats it. You now have a fully integrated virtual server for development. If you have any questions, suggestions, problems or concerns, please let me know in the comments.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/iUYSngKqV0M" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2009/06/18/creating-a-virtual-development-server-using-virtualbox/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2009/06/18/creating-a-virtual-development-server-using-virtualbox/</feedburner:origLink></item>
		<item>
		<title>Javascript Event Library Updated</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/QIRM1n4WQiI/</link>
		<comments>http://www.fliquidstudios.com/2009/06/15/javascript-event-library-updated/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 10:23:35 +0000</pubDate>
		<dc:creator>Christian Biggins</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Fliquid]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Update]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/2009/06/15/javascript-event-library-updated/</guid>
		<description><![CDATA[Just a small post to announce that the Javascript Event Library has been updated with a few new methods and smaller size (reduced variable length, removed semicolons).
The updated code can be viewed and downloaded via our Projects page.
If you encounter any bugs or would like to collaborate in its development, please let me know.
]]></description>
			<content:encoded><![CDATA[<p>Just a small post to announce that the Javascript Event Library has been updated with a few new methods and smaller size (reduced variable length, removed semicolons).</p>
<p>The updated code can be viewed and downloaded via our <a href="http://www.fliquidstudios.com/projects/">Projects</a> page.</p>
<p>If you encounter any bugs or would like to collaborate in its development, please let me know.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/QIRM1n4WQiI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2009/06/15/javascript-event-library-updated/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2009/06/15/javascript-event-library-updated/</feedburner:origLink></item>
		<item>
		<title>5 development techniques to improve software quality</title>
		<link>http://feedproxy.google.com/~r/FliquidStudios/~3/SD2XeWd93gg/</link>
		<comments>http://www.fliquidstudios.com/2009/05/21/5-development-techniques-to-improve-software-quality/#comments</comments>
		<pubDate>Thu, 21 May 2009 03:11:55 +0000</pubDate>
		<dc:creator>Michael Little</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.fliquidstudios.com/?p=284</guid>
		<description><![CDATA[Most of these things you should really already be doing and if you&#8217;re not then I&#8217;d suggest starting to do so right away.
1. Step back and plan
It&#8217;s often hard not to just jump straight in to coding, especially with a project you are excited about. Try to resist that urge by stepping back and taking [...]]]></description>
			<content:encoded><![CDATA[<p>Most of these things you should really already be doing and if you&#8217;re not then I&#8217;d suggest starting to do so right away.</p>
<p><b>1. Step back and plan</b><br />
It&#8217;s often hard not to just jump straight in to coding, especially with a project you are excited about. Try to resist that urge by stepping back and taking a bit of time to think about things before you start typing. Think about the problem are you trying to solve, any difficulties that may arise and come up with a potential solution. Even better than thinking about the problem and solution, write it down somewhere. If you start coding before you&#8217;ve completely got your head around the problem there&#8217;s a very good chance you will end up with little more than a mess.</p>
<p>After all if you start coding a solution before you know what that solution is how are you going to know when you arrive at that solution?</p>
<p><b>2. Document before coding</b><br />
Documentation is another aspect of coding that is too often overlooked. Some developers believe it is not their job to document, others just don&#8217;t get around to it because of time constraints. Documentation of functions/methods and how particular sections of code are supposed to work can help with debugging and avoid the old &#8220;What was I/he/she thinking with this code?&#8221; situation.</p>
<p>I suggest that whenever you create a new class/function/method (or any other relevant piece of code) create the skeleton of it ONLY, then write the documentation. Only once the documentation is done should you think about implementing the guts of the function. This will ensure documentation doesn&#8217;t get forgotten and you will have a much clearer picture of what you are trying to achieve before you set out.</p>
<p><b>3. Adopt a coding standard and stick to it.</b><br />
Use consistent indentation, layout, naming conventions etc across all of your code. It not only makes it easier for you and other to read and modify but it will also make it much easier to debug when you come back to look at the code in a few months time. This is easily one of the most important things you can do to improve the quality of your code but is also one of the most forgotten about or ignored.</p>
<p><b>4. Write test plans and make sure they are used</b><br />
A lot of the time testing is performed very minimally or in a haphazard way. This is bad because leaves you open to miss areas while testing or not discovering obvious problems because the tester does know understand how the software will be used. This is unfortunately always a risk but it can be greatly minimised by writing various test plans and ensuring they are actually used. Test plans can be quite complex and extensive or simple use cases that are followed by the tester. Either way they are an excellent way of showing what has been tested and over time they can be expanded to cover more of your software.</p>
<p>Similarly to the writing of documentation for each class/function/method when they are created you should additionally create a set of tests for every function as or before it is coded. Again the tests can be expanded over time and are a great way of performing quick regression checks.</p>
<p><b>5. Reviews</b><br />
This is by no means a new concept but it is definitely one that is under-utilised. Developers are often afraid of peer reviews because they don&#8217;t like their code being criticised and other developers can often be quite harsh. Don&#8217;t take it personally, it can be very useful to&nbsp; have someone else&#8217;s eyes spot things you missed and after a few reviews your code will more than likely start to improve in general.</p>
<p>In addition to peer reviews, review your own code. Go back and have a quick read of what you&#8217;ve done in 1 week, 1 month, 4 months and 12 months later if you can. You&#8217;re almost guaranteed to come up with a better solution than you did before. Although you may not be able to implement your new ideas in that old project you may be able to use them in future.</p>
<p><b>Conclusion</b><br />
I am a big believer in continually trying to improve my skills, knowledge and most of all coding standards. By using the techniques above (as well as others) the quality of software can be improved and over time so will your skills. Let us know your thoughts on the techniques listed above. Do you use them already? Do you think they will work for you or do you hate the idea altogether?</p>
<p>Also, I would love to hear of any other techniques people use relating to improving software quality. Leave a comment and let us know.</p>
<img src="http://feeds.feedburner.com/~r/FliquidStudios/~4/SD2XeWd93gg" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.fliquidstudios.com/2009/05/21/5-development-techniques-to-improve-software-quality/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		<feedburner:origLink>http://www.fliquidstudios.com/2009/05/21/5-development-techniques-to-improve-software-quality/</feedburner:origLink></item>
	</channel>
</rss>
