Friday, July 3, 2009

10 Ways to Avoid Writing Crappy Code

1. Learn OOP and common OO principles

This is an absolute requirement. If you are still coding procedural, this is no small task. What are you waiting for?

1. Employ Test Driven Design

Code that is buggy or simply doesn't work at all can safely be considered "crappy code". TDD gives you the confidence that your code works, and the side effects force better and more flexible software design.
If you are not familiar with TDD yet, and this post has prompted you to try it, be warned: at first it will seem very cumbersome. What definitely will help is this piece of advice, which is at the core of Test Driven Design: don't write tests afterwards, write them first. Without going to much into the details, and somewhat simplified the general mantra is this: write a test first, make it work by writing the application code, refactor, write another test, make it work, refactor, etc etc. It's a cycle. The application code follows the test code, not the other way around.
I recommend PHPUnit. It has the most features and the largest adoption.

2. Refactor, refactor, refactor

Refactoring means "to improve the design of existing code". Making changes to code results in an increasing loss of quality of that code, this is known as "software decay". To battle this phenomenon, you have to constantly evaluate if the code hasn't lost it's quality, and look for opportunities to improve the design beyond it's original. But there's a catch. And it isn't the time that refactoring takes, if you do it properly you'll save those hours by having avoided software decay. It is the risk of change.
I can understand if you are hesitant to change code that works (at least for now). But this is where number two comes back into play: as long as you've written the right tests, you can make sure your changes don't break anything.

3. Simpler is better

Your mind should constantly be waging a battle between simplicity and flexibility. Avoid unnecessary complication.

4. Use Design Patterns

Design Patterns describe real world software design problem and solutions. Make sure you are familiar with them, buy some books. If you encounter a design problem that seems familiar take your trusty GoF and PoEAA from the shelf and look it up.

5. Don't Use Design Patterns

Once you are familiar with Design Patterns, or even just with the existence of them, it can be tempting to start sprinkling pattern implementations over your application code, just because you can. Don't. Remember a Design Pattern consists of a problem and one or more solutions to that problem. Until you have the problem, don't use the solution.

6. Accept the limitations of your language

Believe me, I know that as a programmer it is difficult to accept limitations on bending your code to your will, but trying to change the behaviour of PHP is not the solution. PHP has limitations, you'll have to live with them. If you try to "patch" them, chances are you will do more harm than good.

7. Pretend you are writing a book

It has been said that "code should be easy to read rather than easy to write". Maybe somebody else will need to understand your code at some stage. Maybe two years from now, you will revisit this code and need to re-learn it's inner workings.
Semantics, meaningful docblocks and clear execution flow are everything. Imagine reading an instruction manual without pictures, filled with meaningless abbreviations, and with the pages in arbitrary order, without page numbers. That's how someone, maybe you, will feel if you ignore this advice.

8. Peer Review

Believe it or not, you don't know everything and you aren't always right. Nobody is. Getting a "second opinion" can only improve the end result.

9. E_STRICT is your friend

Make sure your code runs properly with E_STRICT turned on. Although, if you have gotten this far, I don't think that will be a problem.

10. Create a distinction between "source code" and a "build"

Even though PHP is an interpreted language, this is an important distinction in my opinion, even though practically noone employs this in the PHP world. A build in PHP is a copy of (part of) the source code, which includes assets like HTML, CSS and JavaScript, and is stripped of anything not necessary for running the application. Maybe your build is a Phar file, or maybe you have combined some source files into a single file (like the guys at Doctrine do). Maybe you can provide different build of the same project to server different purposes..
How does this help you avoid crappy code? It allows you to have the source code and build differ, avoiding any compromises you might be tempted to make to facilitate runing or developing the application. Bonus points if you allow the user to choose between placing everything in the server document root or just a bootstrap and the static files.

There are various build tools available, personally I use PHPUnderControl, which is a patch for CruiseControl and gives you a variety of build server features. It uses Ant by default, but I also use Phing.

Thursday, July 2, 2009

10 Signs of Crappy PHP Software

Like it or not, as a professional developer, sooner or later you are going to do some customising (if you are lucky, "extending") of existing software.
If you are not familiar with the software, it is good advice to look into it before accepting the job. I had to learn that the hard way. But how do you recognize crappy applications without getting knee deep into the code? 10 pointers to identify crappy PHP software quickly...
1. The software tries to reinvent the object model, or "fix" language features.

See if you can find a class called "Object". If you find it, it's a pretty clear indication that the author is in the business of trying to reinvent the object model (most commonly because of his own lacking understanding of OO). It is safe to assume that his "fixes" won't stop there. Unplug your phone and hide under your desk.
2. The code includes user defined global variables

A search in the code for "global" or "$GLOBALS" may reveal something like this:
global $database, $my, $mainframe;
The infamous global variable. If you can tell me what those last two variables contain you are either intimate with the software I pulled it from, or you're psychic. Unlimited bonus points if you can say what code has had it's claws on it before execution flow got to this point. In short, steer well clear.
3. Scattered HTML and SQL

Search for some common SQL and HTML strings. You should be able to determine very quickly whether these are appropriate places for HTML or SQL. If you find HTML and SQL in the same file, "crappyness" is most definitely confirmed.
4. Classes do too much

Find the 3 largest class files by bit size. Take a look at the class name. Does it indicate a distinct responsibility? Look at the methods. Are the tasks they perform closely related? If not, run away screaming.
5. Lots of properties are public or lots of properties are static

If lots of properties are declared "public static", triple your quote. If I have to explain why, maybe there's an open position on the development team of the software for you.
6. Multiple levels of inheritance

More than 2 levels inheritance should be avoided like the plague. I stake my life on the resulting objects having too much unrelated behaviour (ok, maybe not my life, but if you find a proper use of more than 2 levels of inheritance, I'll buy you a beer).
7. The authors try to use Design Patterns

Whether or not the authors have a clue is easily determined by searching for some of the most common design patters. Search the code base and/or documentation for "factory", "decorator", "strategy" etc. If present, you can pretty quickly determine whether the authors know their stuff or are trying to look interesting. That is, if you know how the code should look. If not, refuse to take the project until you do.
8. The software messes with the error level

Well written applications run fine at any error level. Searching the files for /error_level\(.*\)/ should do the trick. In case of hits, try replacing the value with E_STRICT. That's little more than a formality though.
9. In the code base, there is a directory called "core"

This is usually used as an excuse to have the whole application dependent on whatever is in there. Despite the appeal of the term (it does make the contents sound pretty cool and important), defining a "core" is a sign of bad design.
10. The software uses it's own template language.

Be afraid. Very afraid. These guys are definitely in the business of reinventing the wheel. Ignore this warning and you will find yourself spending the better part of a day simulating a "for" loop.



Tuesday, June 23, 2009

Using MySQL Administrator with WampServer

For those readers who do not develop PHP on Windows platform WampServer is probably the most popular Apache + MySQL + PHP package for Windows. MySQL Administrator on the other hand, is a part of MySQL GUI Tools package.

The problem with this pair, is that they don't want to work together. At least not right out of box. MySQL Administrator fails to find mysql service process as installed by WampServer. This leads to infamous 'Could not find settings' error message.

You still will be able to use MySQL Administrator, but some of its features will be unavailable - among them quite important 'Startup variables' that lets you configure your server.

The reason is simple. WampServer keeps MySQL's config file in a directory, that is not checked by MySQL Administrator's searching algorithm.

Luckily, the solution is also simple.

Open registry editor
Windows XP: Go to Start > Run... type in regedit and press Enter
Vista: Go to Start, type regedit into search box and press Enter

A word of warning: be careful when using registry editor, as you might break your system if you change wrong variables.

Using tree on the left go to:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\wampmysqld

In the window on the right find ImagePath variable, double click it's name.

In the dialog that opens you should see something like this:
c:\wamp\bin\mysql\mysql5.1.33\bin\mysqld.exe wampmysqld
(MySQL's version may vary)

Change it like this:
"c:\wamp\bin\mysql\mysql5.1.33\bin\mysqld.exe" --defaults-file="c:\wamp\bin\mysql\mysql5.1.33\my.ini" wampmysqld
(be careful not to miss any double quotes!

Close registry editor, then restart you MySQL server from WampServer's tray menu.

MySQL Administrator should work fine now.

That would be it ;)

----

MySQL Forums post, where I've found this solution|Database Software Development by Expert Developers, UK

Thursday, June 18, 2009

SSH Auto-mount Network Share

(Beware - This blog/tutorial is directed towards linux based users)
When doing any type of work, especially web work, one of the royal pains is FTPing to your server, or any type of file transfer. Well now you can make it quick and painless. Let me introduce SSHFS. There are 3 major components when creating the SSHFS, and I will guide you through creating and installing all of the necessary steps. Now you can mount and use your file system to automatically upload files and folders to your server with ease.

The 3 Major components:

  1. SSH Automatic Login
  2. Install SSHFS
  3. Mount your folder(s)

SSH Automatic Login

Run this command (with the obvious variable substitutions). It should create a public ssh key on your server.

ssh-copy-id [-i [identity_file]] [user@]machine
  1. ssh-keygen -t dsa
  2. ssh-copy-id user@machiner.

Check to make sure it's there, the file should be called, "authorized_keys".

ls -al ~/.ssh/

If you're having trouble with this part, you can reference this tutorial which breaks this component into smaller steps: SSH Automatic Login.

Install SSHFS

sudo apt-get install sshfs

Or use whatever package manager your distribution provides.

Mount

Create a shell script, we'll call it "mount.sh", and add the contents:

sshfs [user]@[your_server].com:/dir/on/server /dir/to/mount

Run the script:

./mount.sh

Go to the mounted directory and run the 'ls' command to make sure all of your files/folders from your server show up in your local directory.

After you have this successfully working you should at it to your startup scripts.

System >> Preferences >> Sessions >> [add_a_new_entry]

You should be all set. You should have an automatic SSH login (no prompt for a password) from your computer to your server and a mounted folder to your server that acts as an automatic FTP client. The files in your mounted directory should be synced with that of your server. Now all you have to do is move or copy your desired files/folders into the mounted directory, and voila, they're on your server.





ceXpress-Products Facebook Page

Cexpress products Blog

Friday, May 29, 2009

MySQL University: Boosting Performance With MySQL 5.1 Partitioning

It's been some time some time since we had a MySQL Uni session subject that could be interesting to an 'average' PHP developer. The one that's going to take place next Thursday will definitely be of this sort.

Introduced in MySQL 5.1, partitioning lets you divide your tables into smaller chunks of data... while still keeping them in one table. No more need for `invoices2006`, `invoices2007`, `invoices2008` tables to cope with archival data, no more wicked UNIONs. Now you can tell MySQL to keep invoices (or whatever you need to keep) from one year separate from all other years, thus improving queries that only deal with records from one year.

That's just a simple example, as there are much more to partitioning than that. I urge you therefore to attend MySQL Uni's Dimdim session this Thursday, June 4th at 13:00GMT.

The session will be presented by Giuseppe Maxia a.k.a. The Data Charmer. I attended one of his sessions in the past, and he seems like a very interesting person to listen to.Check the MySQL University home page for details (and possible last minute schedule changes!)For more information about MySQL University, see my introductory post

Saturday, April 25, 2009

Personality Development - a slide I liked

Too much information about the MySQL TIMESTAMP

Source:http://www.gizmola.com/blog/archives/93-Too-much-information-about-the-MySQL-TIMESTAMP.html

The MySQL timestamp is an oddity, being both a mySQL "Data Type" as well as a type of specialty column that provides a built in default. It doesn't help matters, that the timestamp was changed significantly around mysql version 4.1.

The Old TIMESTAMP


In older mysql versions, the TIMESTAMP was not in the same format as a DateTime column, and you could also set up truncation by defining the TIMESTAMP to have a fixed size. For example, you could define a TIMESTAMP column to be a TIMESTAMP(4) which would then only store the 4 digit Year portion of a DateTime value. I won't go into much detail on the pre version 4.1 TIMESTAMP, however, if you're stuck with an older version of MySQL I recommend you read the manual carefully before you attempt to use any of the information here. I'm going to concentrate on the current TIMESTAMP.

TIMESTAMP Properties


At its most fundamental, the TIMESTAMP is really nothing more than a Unix TimeStamp, which is to say, that internally it is stored as an integer value of seconds. Where a MySQL DATETIME column can be used to store any date and time from Jan 1, 1000 to 12/31/9999, the TIMESTAMP is limited in the same ways that the Unix timestamp is currently limited -- it can only store values from Jan 1, 1970 to Jan 9, 2038.

Those familiar with Unix design, will recognize the Jan 9, 2038 date as being the next big "Y2K" computing panic, and if you're young enough, you may realize a large payday in your future, selling remediation services to companies in roughly another 28 years. The folks at http://www.y2038.com/ are already estimating this to be as much as a 10 trillion dollar jackpot, although no doubt by that time most of the coding will be done by the Morlocks from their underground cave cities. Outsourcing of IT to Morlocks will be a major industry trend by the year 2020, mark my words.

Saving bytes


MySQL stores a timestamp as a 32 bit integer, which of course requires 4 bytes of storage. This is one reason why you might want to use a TIMESTAMP over a DATETIME, which requires 8 bytes. Primarily, people look to the TIMESTAMP because, as its name implies, it can be utilized to stamp the time on a row at the point it's inserted. Let's take a look at a mysql TIMESTAMP in action.

First let's create a table with a single TIMESTAMP column in it. We will not refer to this column, and observe what happens when we insert a new row into the table. In case you're keeping score:
mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 5.0.45 |
+-----------+
1 row in set (0.00 sec)


  1. CREATE TABLE atimestamp (id INT PRIMARY KEY AUTO_INCREMENT, justnow DATETIME, created TIMESTAMP);


mysql> describe atimestamp;
+---------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| justnow | datetime | YES | | NULL | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------+-----------+------+-----+-------------------+----------------+
3 rows in set (0.00 sec)


So here we have the table, along with a datetime column that we will set to the magic value of NOW().

mysql> insert into atimestamp (justnow) values (NOW());
Query OK, 1 row affected (0.00 sec)

mysql> select * from atimestamp;
+----+---------------------+---------------------+
| id | justnow | created |
+----+---------------------+---------------------+
| 1 | 2009-04-23 14:29:58 | 2009-04-23 14:29:58 |
+----+---------------------+---------------------+
1 row in set (0.00 sec)


Just as one would hope, MySQL automatically sets the value of TIMESTAMP column I named "created" to be the same as the Server time. So if our primary goal is to have a column that keeps track of when the row was created, our TIMESTAMP does a great job.

Or does it?


Stopping an UPDATE from overwriting the TIMESTAMP



What happens if, at later time, we UPDATE a column in the table?

mysql> update atimestamp set justnow = NOW();
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from atimestamp;
+----+---------------------+---------------------+
| id | justnow | created |
+----+---------------------+---------------------+
| 1 | 2009-04-23 14:30:32 | 2009-04-23 14:30:32 |
+----+---------------------+---------------------+
1 row in set (0.00 sec)


This is not good. Our created time has been lost, because the default behavior of a TIMESTAMP is to update the value to NOW(), any time the row is changed.

The TIMESTAMP Defaults


Setting a column to be a MySQL TIMESTAMP is equivalent to also giving the column a default of CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP. For those not familiar with Mysql Defaults, when creating a table, you can specify a default value for a column to receive if it is not specifically assigned a value during an INSERT. You do this using the DEFAULT keyword, and for all columns other than a TIMESTAMP this must be a constant value. Timestamp columns can specify the CURRENT_TIMESTAMP default which tells mySQL to default this column to NOW().

Stopping UPDATE on TIMESTAMP


The only way not to get the update behavior is to specifically declare the TIMESTAMP to DEFAULT CURRENT_TIMESTAMP. This seems to me to defeat the purpose of having the default behavior in the first place but might be understandable if it was possible for you to have a second TIMESTAMP column, perhaps named "updated".

Unfortunately, you can't have one TIMESTAMP with DEFAULT CURRENT_TIMESTAMP, and a second one with ON UPDATE CURRENT_TIMESTAMP. More often than not, what people really want is only the DEFAULT CURRENT_TIMESTAMP behavior, so it's very important to remember this workaround, if you are using a TIMESTAMP as for example, the "signup date" in a User table. See this in action below:

  1. CREATE TABLE atimestamp (id INT PRIMARY KEY AUTO_INCREMENT, justnow DATETIME, created TIMESTAMP DEFAULT CURRENT_TIMESTAMP);


mysql> describe atimestamp;
+---------+-----------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-----------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| justnow | datetime | YES | | NULL | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------+-----------+------+-----+-------------------+----------------+
3 rows in set (0.00 sec)

mysql> insert into atimestamp (justnow) values (NOW());
Query OK, 1 row affected (0.00 sec)

mysql> select * from atimestamp;
+----+---------------------+---------------------+
| id | justnow | created |
+----+---------------------+---------------------+
| 1 | 2009-04-23 18:15:38 | 2009-04-23 18:15:38 |
+----+---------------------+---------------------+
1 row in set (0.00 sec)

mysql> update atimestamp set justnow = NOW();
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from atimestamp;
+----+---------------------+---------------------+
| id | justnow | created |
+----+---------------------+---------------------+
| 1 | 2009-04-23 18:15:56 | 2009-04-23 18:15:38 |
+----+---------------------+---------------------+
1 row in set (0.00 sec)



Now we have automatic timestamping on INSERT, but without the timestamp being overwritten on UPDATE.

What about an UPDATE only TIMESTAMP?


Perhaps there's a really good reason to dedicate a TIMESTAMP to only apply the time when the row is updated. I can't think of one, but for the sake of completeness, here's how you can define the Default.

  1. CREATE TABLE atimestamp (id INT PRIMARY KEY AUTO_INCREMENT, justnow DATETIME, updated TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP);


mysql> describe atimestamp;
+---------+-----------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-----------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| justnow | datetime | YES | | NULL | |
| updated | timestamp | NO | | 0000-00-00 00:00:00 | |
+---------+-----------+------+-----+---------------------+----------------+
3 rows in set (0.00 sec)

mysql> insert into atimestamp (justnow) values (NOW());
Query OK, 1 row affected (0.00 sec)

mysql> select * from atimestamp;
+----+---------------------+---------------------+
| id | justnow | updated |
+----+---------------------+---------------------+
| 1 | 2009-04-24 23:33:56 | 0000-00-00 00:00:00 |
+----+---------------------+---------------------+
1 row in set (0.01 sec)

mysql> update atimestamp set justnow = NOW();
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from atimestamp;
+----+---------------------+---------------------+
| id | justnow | updated |
+----+---------------------+---------------------+
| 1 | 2009-04-24 23:34:19 | 2009-04-24 23:34:19 |
+----+---------------------+---------------------+
1 row in set (0.00 sec)



Many Timestamps, but only one that's magical


MySQL will allow you to declare multiple columns of type TIMESTAMP, but only the first timestamp in the table will have the built in Default.

  1. CREATE TABLE bigtimestamp (id INT PRIMARY KEY AUTO_INCREMENT, justnow DATETIME, created TIMESTAMP, updated TIMESTAMP, verified TIMESTAMP);


mysql> describe bigtimestamp;
+----------+-----------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-----------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| justnow | datetime | YES | | NULL | |
| created | timestamp | NO | | CURRENT_TIMESTAMP | |
| updated | timestamp | NO | | 0000-00-00 00:00:00 | |
| verified | timestamp | NO | | 0000-00-00 00:00:00 | |
+----------+-----------+------+-----+---------------------+----------------+
5 rows in set (0.00 sec)

mysql> insert into bigtimestamp (justnow) values (NOW());
Query OK, 1 row affected (0.01 sec)

mysql> select * from bigtimestamp;
+----+---------------------+---------------------+---------------------+---------------------+
| id | justnow | created | updated | verified |
+----+---------------------+---------------------+---------------------+---------------------+
| 1 | 2009-04-24 23:39:19 | 2009-04-24 23:39:19 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |
+----+---------------------+---------------------+---------------------+---------------------+
1 row in set (0.00 sec)


Even with this limitation, it may still be a good idea to declare your Date columns as TIMESTAMP type, as the savings of 4 bytes per date per row can easily be significant if your table will have a lot of rows in it.

Single table Insert and Update Timestamp Workaround


It is actually possible to trick mysql into providing the default timestamp behavior for "created' and "updated" columns, despite the documented limitation of only having one default timestamp per table. If you define the first timestamp column to have a default of 0, while also being NOT NULL, you can trick mysql into supplying today's date by explicitly setting the column to be NULL on insert. In this case, mySQL decides to be helpful and for no logical reason, to set the value to NOW(). The second TIMESTAMP which has the explict TIMESTAMP defaults, works normally, and is set to NOW() on insert and update.

  1. CREATE TABLE atimestamp (id INT PRIMARY KEY AUTO_INCREMENT, justnow DATETIME, created TIMESTAMP NOT NULL DEFAULT 0, updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);


mysql> describe atimestamp;
+---------+-----------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+-----------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| justnow | datetime | YES | | NULL | |
| created | timestamp | NO | | 0000-00-00 00:00:00 | |
| updated | timestamp | NO | | CURRENT_TIMESTAMP | |
+---------+-----------+------+-----+---------------------+----------------+
4 rows in set (0.00 sec)

mysql> insert into atimestamp (justnow) values (NOW());
Query OK, 1 row affected (0.00 sec)

mysql> select * from atimestamp;
+----+---------------------+---------------------+---------------------+
| id | justnow | created | updated |
+----+---------------------+---------------------+---------------------+
| 1 | 2009-04-24 23:54:23 | 0000-00-00 00:00:00 | 2009-04-24 23:54:23 |
+----+---------------------+---------------------+---------------------+
1 row in set (0.00 sec)

mysql> insert into atimestamp (created, justnow) values (NULL, NOW());
Query OK, 1 row affected (0.00 sec)

mysql> select * from atimestamp;
+----+---------------------+---------------------+---------------------+
| id | justnow | created | updated |
+----+---------------------+---------------------+---------------------+
| 1 | 2009-04-24 23:54:23 | 0000-00-00 00:00:00 | 2009-04-24 23:54:23 |
| 2 | 2009-04-24 23:55:35 | 2009-04-24 23:55:35 | 2009-04-24 23:55:35 |
+----+---------------------+---------------------+---------------------+
2 rows in set (0.00 sec)

mysql> update atimestamp set justnow=NOW() WHERE id = 2;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> select * from atimestamp;
+----+---------------------+---------------------+---------------------+
| id | justnow | created | updated |
+----+---------------------+---------------------+---------------------+
| 1 | 2009-04-24 23:54:23 | 0000-00-00 00:00:00 | 2009-04-24 23:54:23 |
| 2 | 2009-04-24 23:56:48 | 2009-04-24 23:55:35 | 2009-04-24 23:56:48 |
+----+---------------------+---------------------+---------------------+
2 rows in set (0.00 sec)


While this technique works at present, I would consider it an undocumented hack, based on a side effect. It also requires you to explicitly specify NULL in the values for the created column. If you forget to reference the column in the INSERT statement, it will not set the value to NOW() as illustrated above. This technique works for now, but who knows what will happen in future versions of mySQL? Use at your own risk.