Tuesday, 26 April 2011

Efficient Age From Date of Birth Calculation - PHP edition

Well thought I would have a look at the same set of methods in PHP as I did in MS SQL.  The order of efficiency did change somewhat, which was certainly interesting to me.  Below is my simple code.

$timeformatted = date("Y-m-d",strtotime('20th March 1954'));


//Start test 1
$time_start = microtime(true);


$datetime1 = new DateTime($timeformatted);
$datetime2 = new DateTime("now");
$interval = date_diff($datetime1, $datetime2);
echo "Test1".$interval->y;


$time_end = microtime(true);
$time = ($time_end - $time_start)*100;
echo "$time ms";


//start test2
$time_start2 = microtime(true);


$japDate1 = str_replace("-","",$timeformatted);
$japDate2 = date("Ymd",time());


$answer = floor(($japDate2 - $japDate1)/10000);
echo "Test2 $answer";
$time_end2 = microtime(true);
$time2 = ($time_end2 - $time_start2)*100;
echo "$time2 ms";


//start test 3
$time_start3 = microtime(true);


$japDate3 = explode("-",$timeformatted);
$japDate4 = date("Y-m-d",time());
$japDate5 = explode("-",$japDate4);


if($japDate3[1]>$japDate5[1]|| ($japDate3[1]==$japDate5[1] && $japDate3[2]>=$japDate5[2])){
  $answer3 = $japDate5[0] - $japDate3[0] - 1;
} else {
  $answer3 = $japDate5[0] - $japDate3[0];
}


echo "Test3 $answer3";
$time_end3 = microtime(true);
$time3 = ($time_end3 - $time_start3)*100;
echo "$time3 ms";

On my work PC this generated the following timings

Test 1: 0.021505355834961 ms
Test 2: 0.010085105895996 ms
Test 3: 0.010514259338379 ms

Well as you can see for all intents and purposes test 2 and test 3 are equal in performance, and test 1 performs at half the speed.  Although test 1 is definitely the poorest at producing ages, obviously if you were to re-use the data objects later within the same section of code for additional purposes such as a birthday count down, then the expensive data object creation time could end up being as efficient as the other versions.

It is interesting the difference in performance between the two systems, and it suggests that as a generic solution that subtracting the date of birth in Japanese date format is generally the most efficient method across languages and easiest to understand.

Wednesday, 20 April 2011

How to make CSS3 Windows 7 buttons

Just playing around with the lovely CSS3 controls and decided to see if I could generally replicate the Window 7 style buttons without images.  Well I have pretty much achieved the same effect using the CSS below.

input[type="button"] 
{
  cursor:pointer; 
  border: 1px solid #707070;
  background-color: #F0F0F0;
  border-radius: 4px;
  -moz-border-radius: 4px;
  -webkit-border-radius: 4px;
  box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #DDD;
  -o-box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #DDD;
  -webkit-box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #DDD;
  -moz-box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #DDD;
  padding: 3px 6px;
}

input[type="button"]:hover 
{
  cursor:pointer;
  background-color: #EAF6FD;
  border: 1px solid #3C7FB1;
  box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #BEE6FD, 0 0 3px #A7D9F5;
  -o-box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #BEE6FD, 0 0 3px #A7D9F5;
  -webkit-box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #BEE6FD, 0 0 3px #A7D9F5;
  -moz-box-shadow: inset 0 1px 2px #fff, inset 0 -0.7em #BEE6FD, 0 0 3px #A7D9F5;
}
input[type="button"][disabled], input[type="button"][disabled]:hover
{
  border: 1px solid #ADB2B5;
  text-shadow: 1px 1px #fff;
  cursor:default;
  background-color: #F4F4F4;
  box-shadow: inset 0 1px 2px #fff;
  -o-box-shadow: inset 0 1px 2px #fff;
  -webkit-box-shadow: inset 0 1px 2px #fff;
  -moz-box-shadow: inset 0 1px 2px #fff;
}

CSS3 is fun, wish IE6,7,8 would suddenly disappear ;)

Tuesday, 19 April 2011

If you have nothing to do make work for yourself...

Developer1: OK so we need to store lots of data, what should we use?
Developer2: How about an SQL database?
Project manager: Nah, that seems far too easy, lets use a hashed file system with no data typing and write all the engine transaction code ourselves.

Developer1: Well we need the application to be client server based?
Developer2: Shall we use an MVC model and a "dumb" database?
Project manager: Nah, that's just one of those established paradigms that all the boring people use.  How about we put all of the business logic in stored procedures and all of the database validation in the client, yep sounds good.

Developer1: We need this to communicate over long distances?
Developer2: How about we use a web browser and HTTPS?
Project manager: What use established protocols, are you mad, we should create our own communications mechanism.

Developer1: Which language should we work in?
Developer2: Well I guess a modern language would be good to take advantage of the most up to date libraries and get good compatibility which current and future products, maybe even use an application framework.
Project manager: Huh you must be an amateur, you should be written in at least 4 languages, making sure that you do not have any experience writing in at least 2 of them, oh and you must be using ones that are no longer supported.  Yeah much more sensible to use Delphi, Basic+, C# and Java.

Developer1: What platform should we aim for?
Developer2: Well if you make it a browser app well then it will work on all platforms even mobile ones.
Project manager: Nope, lets make it a Windows only app, and make sure the UI is not written in anything new, you wouldn't want to have easy Windows API access, that would be for wimps.

Now I understand the arguments against rewriting an application which is successful and still selling, however, the cost of completely restructuring the internals without being able to follow any best practice guidance and hand code everything is surely far worse and will lead to an unmaintainable project.

Monday, 11 April 2011

Efficient Age From Date of Birth Calculation

I have been playing around with MS SQL and I was wondering what would be the most efficient method to gather a users age.

Calculations involving dates should always be considered from their most tricky state, if you consider that you might need to take into account UTC time, leap years, time zones it all starts to add up to complexity that you can too easily trip up over. 

So my first thought when someone asks me to calculate the age from a DOB field is to "cheat" and use the built in languages tools. Most languages have some form of datediff function that can be used to calculate the time between two dates.  However is this going to be the most efficient method?

I thought I would test a couple of methods on MS SQL to see the performance changes.  All tests were performed on a low spec laptop on MS SQL Express on a set of 100 random date of births

First method

SELECT floor(datediff(day,[dob],current_timestamp) / 365.25)

Well this is nice and succinct but does suffer a bit from the fact that DATEDIFF rounds up.  I would love to just do DATEDIFF(year... but this will only provide the correct age once per year)

This method gave me the answer in 0.296 secs

Second method

SELECT (convert(int,convert(varchar(8),current_timestamp,112))
 - convert(int,convert(varchar(8),[dob],112)))/ 10000

Well some basic maths relying on Japanese date format gives me the same answer in 0.343 secs

Third method subtract the years from each other and then reduce by 1 if the

 SELECT CASE WHEN convert(int,substring(CONVERT(varchar(8), [dob] , 112),5,4)) >= convert(int,substring(CONVERT(varchar(8), CURRENT_TIMESTAMP , 112),5,4))
THEN convert(int,substring(CONVERT(varchar(8), CURRENT_TIMESTAMP , 112),1,4)) - convert(int,substring(CONVERT(varchar(8), [dob] , 112),1,4)) -1
ELSE convert(int,substring(CONVERT(varchar(8), CURRENT_TIMESTAMP , 112),1,4)) - convert(int,substring(CONVERT(varchar(8), [dob] , 112),1,4))
END
 This method took 0.420 seconds.

Looking at this the first two methods are for all intents and purposes identical to just the selecting the raw dob value, which indicates to me that there is very little efficiency to be gained in this process.  Even my messy CASE version is pretty swift.

Although it is fun to do this in the database it is really much easier to do this at the higher level and intial testing of this suggest to me that the overhead is so minimal that the methods I have outlined are only really useful for quick reporting when you just need the calculation and have an available SQL interface

Friday, 8 April 2011

Is the Moodle project dead?

While you may have heard the design mantra "Content is King", perhaps you might not be familiar with the development mantra that "Documentation is King".

In June 2010 I developed a Block for Moodle to connect Moodle to another piece of software.  This block was developed for version 1.9, using the documentation based on the instructions provided in http://docs.moodle.org/en/Development:Blocks.  Although the instructions were sparse I managed to create a working Block.

A few months later I tested it against the latest release version 1.9.8.  It was all still working.  Shortly after this a customer asked if it worked on version 2.0.  Unfortunately when I tested in version 2 my module did not show up.

Assuming that they had not changed too much I started looking through the documentation.  I was stuck for a little while with the version.php section as I initially assumed I should be entering

$this->version = 2004111200;

This through me for a while because this will actually kill Moodle completely with no error messages...  The correct value is

$plugin->version = 2004111200;

Which is about as obvious as any undocumented code.

Shortly after my break through in this section there is the wonderful section

TODO: New settings.php method

Well what a great help.  It appears this method has been in Moodle since 2009, but as of April 2011 no one has seen fit to mention it, despite it replacing config_global.html.  I am not aware of a successful project of this nature that does not have a complete tutorial on how to create a simple add-on.  

It is the most frustrating thing to do for any developer, break backwards compatibility and not provide the appropriate documentation on the requirements to make your code compatible.  While those who make a direct living from your product might have the time and the resource to scourer through source code those on the fringes that are also adding significant value to your product do not.  

Documentation is King, programming languages and software grow when it is in abundence and suffer when there is a shortage.  Lack of documentation over 2 years after you introduce a new method and 5 months after you release the product is essentially unacceptable, and the sort of thing that will kill off use of your project.

Thursday, 7 April 2011

E-Commerce UI

Really enjoyed this Smashing magazine article on E-Commerce user interface design.  Of course it is not omnipitient and does not go into all of the reason why users abandon the checkout process.

I know from my own experience I have abandoned a checkout because it was not HTTPS.  Some websites only become HTTPS very late on in the process.  As soon as you start sending shopping information you should be on HTTPS pages to emphasise security.  Security experts will be happier and non-experts who have been told about the Green URL bar will also feel a bit better.

Additionally I have been unsure about making a purchase I have proceeded through the checkout process only to decide that I dont really want the item.  Now it could be argued that the persuasiveness of the website was insufficient at the checkout stage, but I feel it was not an easy of use issue and it would be difficult for the UI to have lead to conversion at that stage.

Of course 60%+ does seem like a high loss level and certainly leads me to think that some of it is difficulty in completing the purchase, some loss will always occur.