Monday, October 23, 2006

Ten Commandments for Programmers

  1. Thou shalt not worry about bugs.
  2. Bugs in your software are actually special features.

  3. Thou shalt not fix abort conditions.
  4. Your user has a better chance of winning state lottery than getting the same abort again.

  5. Thou shalt not handle errors.
  6. Error handing was meant for error prone people, neither you or your users are error prone.

  7. Thou shalt not restrict users.
  8. Don't do any editing, let the user input anything, anywhere, anytime. That is being very user friendly.

  9. Thou shalt not optimize.
  10. Your users are very thankful to get the information, they don't worry about speed and efficiency.

  11. Thou shalt not provide help.
  12. If your users can not figure out themselves how to use your software than they are too dumb to deserve the benefits of your software anyway.

  13. Thou shalt not document.
  14. Documentation only comes in handy for making future modifications. You made the software perfect the first time, it will never need modifications.

  15. Thou shalt not hurry.
  16. Only the cute and the mighty should get the program by deadline.

  17. Thou shalt not revise.
  18. Your interpretation of specs was right, you know the users' requirements better than them.

  19. Thou shalt not share.
  20. If other programmers needed some of your code, they should have written it themselves.

Sunday, October 22, 2006

osCommerce Users Group on MySpace

osCommerce Users Group on MySpace

For everyone that has a MySpace account a member named Mark has started a users group. Stop by, join, and network with osC users, developers, designers, and other people interested in the platform.

See you there!

Thursday, October 19, 2006

Zend Certified Engineer

Bobby Easland, Zend Certified Engineer

The Zend Certified Engineer exam has some very tough questions but is well within reach. Programming eCommerce platforms tend to utilize only a small number of core functional areas of the PHP language (file functions, cURL/sockets, DB, etc.) but the exam is very balanced. Anyone that is looking to take the exam should purchase the study guide and maybe even the practice questions book. Both of these helped me to understand the key areas that would be addressed and highlight those areas that I needed to brush up on.

I highly encourage my fellow osCommerce and eCommerce developers to look into the certification exam. It is very satisfying to obtain the certification directly from the architects of the PHP language and also brush up on the skills that may not be commonly used.

I would rate my experience with this certification as a 9 out of 10. Good luck to everyone on their path to certifying your skills and experiences!

Thursday, October 05, 2006

1 Billion Queries Served in 10 days

I've been working on a high volume client completing a very customized platform. They needed such things as support for 10K+ concrete products and virtualization to bring that total up to 100K+. The core modifications for this were extensive but not only did it need to accomodate functional requirements but also scale with enterprise level traffic (10,000+ concurrent users). As if that weren't enough they also needed to integrate seamlessly with their distributor servers for regular XML inventory and orders updates.

The solution for the product virtualization entailed that I first remove the stock osC attrbutes system since IMO it is useless for large catalogs. The shear amount of administration for each product setup would have been several thousand man hours and taken weeks if not months. Another requirement was that inventory be tracked per option. For example, let's say that there is a costume called "Test Costume". There are several attributes (or options) such as size, color, etc. As each one is sold out it needed to be removed from customer display. All of these were easily handled with the highly customized options core.

The next task that was approached was the XML integration with the distributor. Basically this is a complete backoffice integration that syncs not only the inventory levels but also the orders. As the order goes through received, picking, and finally shipped it updates the orders status with customer notifications. In addition, it is fault tolerant with queue redundancy.

Now the fun problem to work on...high traffic volume. For this I naturally selected a clustered configuration with multiple web, load balancers, and DB servers. The cluster currently can support 5K concurrent users without breaking a sweat. In the future if the site encounters a traffic spike (AdWords campaign, etc.) scaling is as easy as adding another node and a fast configuration change in the load balancer.

Since the cluster went live 10 days ago it has served almost 1 billion queries and climbing by about 100 million queries daily. All the while it is sustaining sub .1 second page render times.

...so...for all those people that have been asking me what I've been working on there you go. Want to see the site? Here you go: Halloween Costumes

Monday, July 10, 2006

How to remove session ID appended URLs from the search engine index

A common scenario is for store owners that were not aware of the "Prevent Spider Sessions" option to have several URLs indexed by spiders with the session ID appended. This situation is troublesome and there are a few options to handle referrals sent through the "wild" session ID URL.

However, the true solution to the problem is to REMOVE THE SESSION ID's from the search engine index! So, how hard is it? Pretty easy!

In includes/application_top.php find this code:

Under that paste this code:

This code will redirect the spider to the non-SID URL with a 301 header and over time will remove the session appended URL from the index.

Friday, June 16, 2006

[CONTRIBUTION] Google Sitemap Generator for osCommerce MS-2.2 stores - Categories

After posting the latest version of the Google Sitemap Generator for the catalog products there have been several people request that I also post the one for categories.

So, I have also posted the latest sitemap script for the categories on Digital Point forum as well!

I posted the code inline with the post so that you can inspect it and see how it works. However, I have also attached the file so as to eliminate copy-and-paste errors that will inevitably occur.

If you register on the forum to directly download the file be sure to fill in my screen name (Chemo of course!) so that they know who sent you :-)

Get the new script here: Google Sitemap Generator v1.1 - Categories

Sunday, June 11, 2006

PHP4/MySQL Error Handling with an Observer design pattern

I put up an article on Digg.com just to see what kind of response it gets. If people find it useful I'll post more articles on PHP design patterns and some interesting solutions to common problems. Here's the link: PHP4/MySQL Error Handling with an Observer design pattern. If you dig the article...be sure to give me a DIGG! :-)

Google Sitemap Generator v1.2 (osCommerce MS-2.2) - by Chemo

I have recently joined the Digital Point forum and will be releasing never before published scripts for osCommerce based stores. In addition I'm going to post articles on PHP design patterns, application architecture, and of course example scripts.

The first script that I'm releasing is the followup to my Google Sitemap Generator contribution. As some quick history...exactly 12 hours after I released the v1.0 script I was banned by Harald and the osCommerce team from the community. As a result I never had the change to properly support the contribution and of course was not able to release further developements.

Get the new script here: Google Sitemap Generator v1.2

Sunday, September 04, 2005

PHP4/MySQL Error Handling with an Observer design pattern

I've had several emails from developers about the last blog entry and they all wanted more details on how to implement the Observer pattern for error handling. So, I have started writing an article that will be published by DevShed sometime in the near future.

You can read through the article and stay up to date with the creation. Right now the content is enough for any competent coder to abstract the concept and implement the solution into their application. I'll be adding content to the article as time allows and will hopefully have it finished soon.

While I'm adding content you can always read through it here: PHP4/MySQL Error Handling with an Observer design pattern

Saturday, September 03, 2005

Object registry and Observers...

The build on Chris's application is going well and we have finished implementing the core tiered architecture!

The first step was to construct a simple object registry so that the individual components can be shared via a composite pattern. In a nutshell, it is a basic text book Singleton with a twist. The code looks like this:

Singleton object registry class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
<?php
class Singleton{
    function &
getInstance ($class, $name = ''){
        static
$registry = array();
        
$_instanceName = notNull($name) ? $name : $class;
        if ( !isset(
$registry[$class][$_instanceName]) || !is_object($registry[$class][$_instanceName]) ) {
            
$registry[$class][$_instanceName] =& new $class;
        }
        return
$registry[$class][$_instanceName];
    }
}
?>

The code above is the backbone of the application since it is completely object oriented. The benefit is that the code (classes or objects) are reusable and are able to be shared among all yet only instantiated once. This adds tremendous flexibility while keeping system resource utilization to a minimum as the registry contains only references to the objects and NOT copies of the objects.

The bottom line is that the category pages are rendering in less than .03 seconds with .005 total MySQL time (of course, no caching yet). Almost forgot...only 5 queries! The performance is blistering fast and infinitely scalable * to the limits of MySQL*. The reason for the outstanding performance is that the application was coded from the bottom up with an eye on performance. Since we are sharing objects we eliminated a lot of redundant database queries and processing overhead with multiple instantiation.

In addition, we have implemented an Observer / Listener pattern. This will form the backbone of the first plug-and-play eCommerce shopping cart! Admittingly, our beta code is far from perfect but has tremendous potential. The idea is the place strategic hooks in the business logic (and maybe objects) which will enable notification to event Listeners. Thus far we have implemented 2 core systems that use the Observer pattern: error logging and also script/performance timers. Here is the base class:

Observer pattern class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
<?php
class Observer{
    var
$_observers;
    var
$_message;
    
    function
Observer(){
        
$this->_observers = array();
        
$this->_message = NULL;
    }
# end constructor
    
    
function attach(&$observer){
        
$this->_observers[] =& $observer;
    }
# end function
    
    
function detach(&$observer){
        foreach (
array_keys($this->_observers) as $key ){
            if (
$this->_observers[$key] === $observer){
                unset(
$this->_observers[$key]);
                return;
            }
# end if
        
} # end foreach
    
} # end function
    
    
function notify(){
        foreach (
array_keys($this->_observers) as $key ){
            
$observer =& $this->_observers[$key];
            
$observer->update($this);
        }
# end foreach
    
} # end function
    
    
function getState(){
        return
$this->_message;
    }
# end function
    
    
function setState($info){
        
$this->_message = $info;
        
$this->notify();
    }
# end function    
} # end class
?>

...example instantiation of Observer object and attachment of event hander

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
<?php
/////////
// This code is in application_top.php
/////////
/*
* Initialize the error handler (observer) class as a Singleton
* and attach the screen output object
*/
    
$errorHandler =& Singleton::getInstance('Observer', 'ErrorHandler');
    
$errorHandler->attach(Singleton::getInstance('ScreenOutputErrorLogger'));

/*
* Set the custom error handler function
*/
    
set_error_handler('observerErrorHandler');

/////////
// This code is a general (callback) function
/////////
  
function observerErrorHandler($errno, $errstr, $errfile, $errline, $errcontext){
      
$handler =& Singleton::getInstance('Observer', 'ErrorHandler');
    
$handler->setState( array('number' => $errno,
                              
'msg' => $errstr,
                              
'file' => $errfile,
                              
'line' => $errline
                              
)
                      );
  }
?>

ScreenOutputErrorLogger event handler class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
<?php
class ScreenOutputErrorLogger{
    var
$_errors;
    
    function
ScreenOutputErrorLogger(){
        
$this->_errors = array();
    }
# end constructor
    
    
function update(&$error_handler){
        
$error = $error_handler->getState();
        
$this->_errors[] = $error;
    }
# end function
    
    
function errorCount(){
        return
sizeof($this->_errors);
    }
# end function
    
    
function output($hidden = false){
        if (
$hidden) echo '<!--' . "\n";
        echo
'<h1>Errors:</h1>' . "\n";
        echo
'<pre>' . "\n";
        
print_r($this->_errors);
        echo
'</pre>' . "\n";
        if (
$hidden) echo '//-->' . "\n";
    }
# end function
    
} # end class
?>

The basic operation is that once an Observer is instantiated other objects can register as an event handler. The great benefit is that there can be multiple event handlers for each! So, the ErrorHandler object is instantiated and then directly after that the ScreenOutputErrorLogger is attached. Thus, every non-fatal error that is triggered will send the Listener state to every object that is registered for notification (right now only the screen logger). The flexibility in this system is that other objects can be registered as well. As an example, we will create the email object next which can be registered as an event handler and email the administrator on database errors (instead of killing the script). In fact, we can create as many event handlers as we want. There could easily be a logger event handler that saves the errors to database or text file. The point is that event handlers can be attached and detached as needed without affecting the function of the others.

Another development milestone is the true tiered architecture. We have implemented a classic 4 tier architecture: presentation (template engine), business logic (meat and bones manipulating object interaction), accessor (database access), and persistence (database). We have tested the architecture by placing each tier on a different server that is physically separate from the others. The application performed beautifully and is confirmation the tiered architecture is complete and bug free.

This ground-up build has enabled me to finally implement my custom rolled template engine! There is no PHP in the templates and is completely separate from the code. Thus, inexperienced webmasters can tweak and modify the templates all they want without ever corrupting the core code. In addition, I feel a robust templating engine will afford more designers to quickly create skins. Here is the template class code:

Template engine class

001 
002 
003 
004 
005 
006 
007 
008 
009 
010 
011 
012 
013 
014 
015 
016 
017 
018 
019 
020 
021 
022 
023 
024 
025 
026 
027 
028 
029 
030 
031 
032 
033 
034 
035 
036 
037 
038 
039 
040 
041 
042 
043 
044 
045 
046 
047 
048 
049 
050 
051 
052 
053 
054 
055 
056 
057 
<?php
class Template{
    
    var
$template;
    var
$variables;
    
    function
Template($template = ''){        
        
$this->template = notNull($template) ? file_get_contents($template) : NULL;
    }
# end class constructor
    
    
function Add($var_name, $var_data){
        
$this->variables[$var_name] = $var_data;
    }
# end fucntion Add()

    
function AddMulti($var_data){
        if (
is_array($var_data)){
            foreach (
$var_data as $name => $data ){
                
$this->variables[$name] = $data;
            }
        }
    }
# end fucntion Add()

    
function ResetVars(){
        
$this->variables = NULL;
    }
# end function
    
    
function EvaluateTag($data, $tag, $params = NULL){
        
$_tag = '<' . $tag;
        if (
notNull($params)){
            
$_tag .= ' ' . $params;
        }
        
$_tag .= '>' . $data . '</' . $tag . '>' . "\n";
        return
$_tag;
    }
# end function
    
    
function Remove($vars){
        if (
is_array($vars) ){
            foreach (
$vars as $index => $varname ){
                unset(
$this->variables[$varname] );
            }
# end foreach
        
} else {
            unset(
$this->variables[$vars]);
        }
    }
# end fucntion Add()
    
    
function Evaluate($direct_output = false){
        
$template = addslashes($this->template);        
        foreach (
$this->variables as $variable => $data ){
            $
$variable = $data;
        }
# end foreach        
        
eval("\$template = \"$template\";");        
        if (
$direct_output ) echo stripslashes($template);
        else return
stripslashes($template);        
    }
# end function Evaluate()
    
} # end class
?>

As you can see, we are making good progress on the build and will soon move onto finalizing the beta version of the shopping cart! However, there is still much left to do in order to launch this project. I still need to coordinate the acquisition of a dedicated server to host the project Subversion server. In addition, we need to attract a community to help in the beta testing. It is almost time to launch!

...almost there...stay tuned!