We strive for perfection.  Our goal for each and every project is to make things so reliable and user friendly that once we deliver we don’t hear from our customers until they are ready for their next project.  Throughout our time as Infusionsoft Developers we have found a few things that help us achieve this.  We’ve enumerated these here for your as well as our reference. Some of these are Infusionsoft Specific but many are good practice in general.

If your code doesn’t read like a book, it’s not clean enough.

If you’re reading this, odds are you are a developer and have a knack for technical things.  Unfortunately it’s easy to get yourself in trouble.  One of the keys to keeping things high quality is keeping things simple.  A good litmus test is, if you can look at your code and understand it quickly as if you’re reading an email it’s good.  But if it requires long periods of study to determine what something does, you should probably clean it up some.

Timezones

Not all shared hosts support php 5.3 yet, so we only use date time functions supported by php 5.2

Set php’s default timezone to America/NewYork before computing dates for use with Infusionsoft, and restore it when done.

$original_timezone = date_default_timezone_get();
date_default_timezone_set('America/New_York');
//Your code goes here...
date_default_timezone_set($original_timezone);

Why - Infusionsoft’s servers, although hosted in Arizona are all set for EST time.  EST is probably one of the most popular server time zones.  So, all dates in Infusionsoft’s database are in EST.

Character Sets

Character Sets are one of those things that 99.99% of the time you can ignore, but the other .01% of the time can cause problems that are a real pain to find.  So, first off, go read this: http://www.joelonsoftware.com/articles/Unicode.html  Hopefully now you understand them some.  The biggest problem we find is that most systems treat character sets lazily.  And don’t always specify what character set is being used when data is sent and received, this is fine as long as the sender (browser)  and receiver (server) are on the same wavelength and are expecting the same thing (Frequently UTF-8), but when the sender doesn’t tell the receiver what character set it is using, and the receiver assumes incorrectly you get those funny characters like: � or the funny looking a’s.

Good practices to prevent those funny characters:

Always specify character set in a meta tag in the header on your page.

Why -- Many browsers use the meta tag and or http header to determine what character set to send to the server.   Some servers do not tell the browser what character set they are transmitting data in, usually this isn’t a problem, but to be on the safe side, put this in the head section of your page.  (P.S. The browser also uses this as a hint as to what encoding to send back to the server).  For an example, go to google, now turn on firebug and go to the net tab.  Reload the page, notice how there is the header: “Content-Type: text/html; charset=UTF-8“  Now, do the same thing, but go to www.tradersedge.com.  Notice that there is no charset=UTF-8 in the Content-Type header.  This means the browser has to guess.   Most servers send in UTF-8, so it is a safe bet to put this in the meta tag.

Use htmlspecialchars instead of htmlentities

Why -- htmlentities is old, and doesn’t always get the character set right.  Specifically it defaults to outputting using ISO-8859-1 instead of utf-8 unless you tell it otherwise.  Usually this is fine because most of the characters in ISO-8859-1 are encoded the same in UTF-8, but if you have data in the string that is different in ISO-8859-1 and UTF-8, you have problems (for example, try Alt + 0146), put that in htmlentities and view the output, and then do it with htmlspecialchars.

If you use Infusionsoft’s iSDK, specify the character set in the xmlrpc client.

Add this is the code: $this->client->request_charset_encoding = ‘utf-8′; somewhere after you see this code:  $this->client->setSSLVerifyPeer(FALSE);

Why -- Infusionsoft servers default to utf-8 for xmlrpc requests unless otherwise specified.  Unfortunately the xmlrpc library we all use (the one in the isdk, and our sdk) doesn’t specify the character encoding by default, it just says “Hey Infusionsoft!  I’m sending you some XML!” Which for 99.5% of requests is fine.  But what happens when you try to use the EmailService and your user used MS Word with smart quotes to compose the email going out via the EmailService, and it contains a special quote?  On some php installations this special quote will be put into the xmlrpc request as ISO-8859-1 instead of UTF-8.  Unfortunately, the ISO-8859-1 encoding of the special quotes, are invalid characters in UTF-8, causing Infusionsoft to return a fatal error that looks something like: ” Failed to parse XML-RPC request: Invalid byte 1 of 1-byte UTF-8 sequence.”

Our totally awesome, easy to use,  Open Source Infusionsoft SDK takes care of this for you.

Exception/Error Handling

A whole book could be written on Exception handling but is a brief overview of what we do.

1) Make operations repeatable when possible.

Say you are importing contact details from an imported email into a 3rd party system.  You could just create a new contact and put all the values in, but what if something happens half way through the import?  You would have duplicate contacts if you tried it again. Instead, to make this a repeatable operation, all you have to do is first check and see if the contact exists in the system you are importing too, if it doesn’t then you create one, then you import the data you can from the email into the new or existing contact.  Now, you can run this operation over and over without any adverse effect.

2) Use try catch blocks and exceptions.

Nothing is worse then a script failing with no indication as to why.  When you have a long process (such as importing a contact), wrap it in a try catch block, and inside the functions that are called as part of the process if something goes wrong, just throw an exception with A DESCRIPTIVE error message.  Inside the catch, save the error message somewhere, and display it to the user later.  We usually store error messages in an array like this:
if($applicationInstance['Application']['requires_database'] == 1 || $cake_version > 0){
  $errors = array_merge($errors, $this->_createDatabaseDotIni($mysql_hostname, $databaseName, $username, $password, $deploy_path, $cake_version));
}
if(count($errors) == 0 && $applicationInstance['Application']['has_install'] == 1){
  $errors = array_merge($errors, $this->_runInstall($deploy_hostname, $deploy_path));
}
if(count($errors) == 0 && $cake_version > 0 && $deploy_url_path != ''){
  $errors = array_merge($errors, $this->_changeRewritePathInDotHtAccessFiles($deploy_hostname, $deploy_path));
}
At the end of the script, when we display things to the user, we check the errors array and display them to the user if there are any.  If not, we indicate success somehow.

3) “phone home” when errors occur.

 We have a small library that uses Amazon SES to send an email to errors@novaksolutions.com so it can be investigated. This allows us to be very pro-active and many times fix errors before clients know they have occurred.  By using Amazon SES instead of SMTP, or php’s mail function it also reduces required server configuration and increases environment compatibility / flexibility for our code.  If curl is installed, and outbound https is allowed we’ll get the error message.

Cron Jobs

All cron jobs for a project are centralized at http://someproject/somedir/CronJobs/  While individual jobs are broken up into separate controller functions that CAN be run individualy for testing, all cron jobs should run properly when this single url is put on a cronjob.  If cron jobs need to run at different frequencies, the index method should handle seeing when the last time the cronjob was run and running it or not.  NOT the cron job method.  This is so that the con job method can be invoked at anytime without waiting for a certain time period to elapse.

Granular Commits

We use GIT for everything.  One of the benefits of GIT over SVN is more granular commits.  With SVN it’s difficult to just commit a few files.  Git makes it a piece of cake.  So when you are committing, break up your commits into small commits when it makes sense.  I.e.  You do some work to add fckeditor to a project.  When you are done, and ready to commit, I would make two commits.  One for adding all the fckeditor files, and a second commit for the changes you made to the project itself to use fckeditor.  This makes it easier for code reviewers to audit your changes.

Good Commit Messages

When someone looks at a branches history they should be able to see the progression of the software.  Simple commit messages with a ticket # aren’t enough.  You need to list all features and bugs you fixed on their own line.  Don’t worry about files you changed, however you can say “Fixed a bug in the Users Controller that was causing ___”  or something like that.  You don’t need to write an essay, just make sure it says what you did.