I like Wordpress, although I have to admit that it is not perfect. This is one such line that makes it imperfect. On strict servers, these lines cause me grief.
/**
* PHP4 constructor
*/
function WP_Embed() {
return $this->__construct();
}
Okay, it's important to keep things backwards compatible. Personally, I enjoy playing old games. When I read about Raymond Chen's work keeping old software compatible with new versions of windows, I can't help but feel respect for the guy.
However, this is different. In my example, a team was working to keep the OS (Windows) compatible with old software (SIMCity). Running old software in a new OS is an added value, and is less likely to introduce security errors. In the case of wordpress, the wordpress team is working to keep new software (Wordpress itself), compatible with an old runtime (PHP 4). Well, being able to run a new version of wordpress in PHP 4 is an added value too, but it becomes a major problem when security errors are left unpatched because support for PHP 4 has stopped.
As of this date, it has been two years since the last update for php 4 was released. I know there are still some applications out there that run on PHP 4. I worked on one last year! When I did, I complained about it, but it wasn't my place to tell the client, so they didn't get all the information about how gnarly PHP 4 is.
Well, not all clients can understand that using an old runtime is bad for their system. However, that does not mean that consultants shouldn't try anyway. Clients can be hardheaded, but I think that even the most technophobic Luddite will appreciate being told everything about their system. Giving clients the all the information that they need to make a decision about their investment should be the goal of every consultant.
At the very least, it's going to be their fault if stuff breaks, and there isn't an update to fix the problem. Getting clients to stop using this undead version is the fastest way to get rid of it.
Life Isn't Easy - Suck It Up! Anti-Wisdom isn't easy to come by. One has to actively search for it. Not that it's hard. This blog is about it, in whatever form it may come it.
Friday, August 27, 2010
Saturday, August 21, 2010
What the Hell File Naming
A long time ago, my mentor saw me putting multiple classes in a single C# file. He hit my head, and told me that I was doing something very wrong. He said that files should have just one class so it's easy to find out where something went wrong. Well, he was correct. It's easier to find an error in 1000 files with unique names, compared to scrolling down one gigantic file with the Ctrl+F hotkey.
That way way back in 2004.
Now, I find myself in the same situation. Being a freelance developer, I found myself working on a PHP framework called PHP Road. Now, before anybody googles it, I will warn everybody that it doesn't exist by itself. It apparently became part of the Lemonstand shopping cart platform.
I don't really have anything against it, but somebody who used the PHP Road framework named their files this way.
signupp.php
singuppt.php
signupt.php
Well, apparently, each file did something unique, and each file was important. Care to guess what? Sure, they all had something to do with signing up, but aside from that, what do they do?
Well, it's not easy to guess. Also, guessing takes time. Writing get_included_files() and looking at the source takes time.
I just had to add * REQUIRED to a few input boxes, and I had to check which files were included with PHP code. It shouldn't be that way. Well, that means that files need to be renamed.
It's okay to put some secret code in your file names, but at least make sure it's easy to decipher. Remember, somebody else might be working the code in the future. They also might be strong enough to curb stomp people.
That way way back in 2004.
Now, I find myself in the same situation. Being a freelance developer, I found myself working on a PHP framework called PHP Road. Now, before anybody googles it, I will warn everybody that it doesn't exist by itself. It apparently became part of the Lemonstand shopping cart platform.
I don't really have anything against it, but somebody who used the PHP Road framework named their files this way.
signupp.php
singuppt.php
signupt.php
Well, apparently, each file did something unique, and each file was important. Care to guess what? Sure, they all had something to do with signing up, but aside from that, what do they do?
Well, it's not easy to guess. Also, guessing takes time. Writing get_included_files() and looking at the source takes time.
I just had to add * REQUIRED to a few input boxes, and I had to check which files were included with PHP code. It shouldn't be that way. Well, that means that files need to be renamed.
It's okay to put some secret code in your file names, but at least make sure it's easy to decipher. Remember, somebody else might be working the code in the future. They also might be strong enough to curb stomp people.
Friday, August 13, 2010
Basic TDD in PHP
TDD can be best decribed as writing code that tests other code first. At first, it sounds like a really confusing concept. How does one write code that tests other code? Well, one has to follow two simple rules.
1. The test must be simple. A complicated test needs another test to prove that it works. This spirals into infinity, like a fractal of doom. Alien geometries, anyone?
2. The test must be written first. Because one already knows what the function will do, it's easy to test for it.
Given that, let give a real world example from one of my recent projects.
My client wanted to save the educational attainments of people. There is a database with five columns.
ID - School - Start Year - End Year - Description
The ID column automatically increments, and the Description column is optional. Everything else is required.
My client wants a function to do this. All the data is in the $_POST array. The function will return "Success!" if the information was saved. However, if there is a problem, it will output an error message.
This is what the code file looked like at the start.
function tryToSaveEducation($data) {
return 'Success!';
}
$isTest = array_key_exists('test', $_GET) ?
'true' === $_GET['test'] : false;
if($isTest)
{
# Tests go here
assert('No data' === tryToSaveEducation(null));
}
I shall call this file, TryToSaveEducation.php. Naturally, by navigating to localhost/TryToSaveEducation.php?test=true I can test the method.
On the first run, it's going to fail. There is no if statement that checks for null parameters. Thus, I will modify the function accordingly.
function tryToSaveEducation($data) {
if(is_null($data))
return 'No data';
return 'Success!';
}
Now I just made the test pass!
Now, this might seem like a bad example because the feature I'm testing is a simple null parameter validation. However, remember all the columns that I listed earlier? I'll have to add validation for those columns too! Of course I'm not going to write them all down here. Anyway, now I can check if the function catches a null parameter in one simple action, even if I add 100000 lines of code.
Speaking of code, this is especially useful in large projects that do many different things. Being able to run tests quickly can save a team a lot of time.
Well, maybe I should write about PHPUnit next.
1. The test must be simple. A complicated test needs another test to prove that it works. This spirals into infinity, like a fractal of doom. Alien geometries, anyone?
2. The test must be written first. Because one already knows what the function will do, it's easy to test for it.
Given that, let give a real world example from one of my recent projects.
My client wanted to save the educational attainments of people. There is a database with five columns.
ID - School - Start Year - End Year - Description
The ID column automatically increments, and the Description column is optional. Everything else is required.
My client wants a function to do this. All the data is in the $_POST array. The function will return "Success!" if the information was saved. However, if there is a problem, it will output an error message.
This is what the code file looked like at the start.
function tryToSaveEducation($data) {
return 'Success!';
}
$isTest = array_key_exists('test', $_GET) ?
'true' === $_GET['test'] : false;
if($isTest)
{
# Tests go here
assert('No data' === tryToSaveEducation(null));
}
I shall call this file, TryToSaveEducation.php. Naturally, by navigating to localhost/TryToSaveEducation.php?test=true I can test the method.
On the first run, it's going to fail. There is no if statement that checks for null parameters. Thus, I will modify the function accordingly.
function tryToSaveEducation($data) {
if(is_null($data))
return 'No data';
return 'Success!';
}
Now I just made the test pass!
Now, this might seem like a bad example because the feature I'm testing is a simple null parameter validation. However, remember all the columns that I listed earlier? I'll have to add validation for those columns too! Of course I'm not going to write them all down here. Anyway, now I can check if the function catches a null parameter in one simple action, even if I add 100000 lines of code.
Speaking of code, this is especially useful in large projects that do many different things. Being able to run tests quickly can save a team a lot of time.
Well, maybe I should write about PHPUnit next.
Thursday, August 5, 2010
Conditions from Hell
Here's a good example of refactoring.
if ((($_FILES["file"]["type"][$n] == "image/gif")
|| ($_FILES["file"]["type"][$n] == "image/jpeg")
|| ($_FILES["file"]["type"][$n] == "image/png")
|| ($_FILES["file"]["type"][$n] == "image/pjpeg"))
&& ($_FILES["file"]["size"][$n] < 200000)) {
}
Look how complicated the whole thing is! To think the pseudocode behind it was a simple "make sure the file is a picture and it is a smaller than 200000."
It's easy to refactor though.
$isGif = "image/gif" == $_FILES["file"]["type"][$n];
$isJpg = "image/jpeg" == $_FILES["file"]["type"][$n];
$isPng = "image/png" == $_FILES["file"]["type"][$n];
$isPjpg = "image/pjpeg" == $_FILES["file"]["type"][$n];
$isPic = $isGif || $isJpg || $isPng || $isPjpg;
$smallEnough = 200000 > $_FILES["file"]["size"][$n]
if ($isPic && $smallEnough)
{
}
Sure, there are more temporary variables, but it's easier to read. That will save more time when somebody new picks up the code.
if ((($_FILES["file"]["type"][$n] == "image/gif")
|| ($_FILES["file"]["type"][$n] == "image/jpeg")
|| ($_FILES["file"]["type"][$n] == "image/png")
|| ($_FILES["file"]["type"][$n] == "image/pjpeg"))
&& ($_FILES["file"]["size"][$n] < 200000)) {
}
Look how complicated the whole thing is! To think the pseudocode behind it was a simple "make sure the file is a picture and it is a smaller than 200000."
It's easy to refactor though.
$isGif = "image/gif" == $_FILES["file"]["type"][$n];
$isJpg = "image/jpeg" == $_FILES["file"]["type"][$n];
$isPng = "image/png" == $_FILES["file"]["type"][$n];
$isPjpg = "image/pjpeg" == $_FILES["file"]["type"][$n];
$isPic = $isGif || $isJpg || $isPng || $isPjpg;
$smallEnough = 200000 > $_FILES["file"]["size"][$n]
if ($isPic && $smallEnough)
{
}
Sure, there are more temporary variables, but it's easier to read. That will save more time when somebody new picks up the code.
Subscribe to:
Posts (Atom)