Yesterday I was fortunate enough to attend the Summerside 'instance' of the Global Day of Coderetreat (my first ever) and already I can't wait for the next one.
The day is very difficult to describe without sounding like a cultist, to be honest :) There's something very awesome about being able to slowly, precisely and correctly write code without having any pressure to just 'get it done'.
For those that aren't familiar with the process, ours went something like this: partner up, write some code for 45 minutes then delete it. Add a constraint and repeat. While the goal seems to be "implement Conway's Game of Life", the actual goal, in a way, is to never quite get there :)
For our particular retreat, we started with basically just trying to implement GoL correctly. This means using TDD properly, and slowly implementing the code bit by bit. My first round I got to do it in Java, which is always fun.
After deleting the code, we added the constraint of 'no conditionals'. This time my 'pair' wrote in PHP and surprisingly enough got to the exact some point in the code as the first round (which I found humourous).
After lunch, we added 'use no primitives' (and 'no PHP' :) ). This time my partner and I decided to use Ruby, which was fantastic as I am an absolute beginner, and my team mate was definitely not an expert. We got to spend some time learning RSpec (for testing Ruby code) and we spent a lot of time simply discussing what the constraint meant. It was definitely a difficult thing to wrap our heads around, but this was the point where I suddenly realised that some of our constraints are not necessarily possible with all of the languages that we choose to use. This was definitely a pivotal moment for me. To be honest, it had been brought to my attention at the end of the first constraint, but this time it was me making the realisation by myself :)
Delete. Break. Try again. This time using JS and 'only return self'. Delete. Break. Back to Java and 'no more than 4 lines per method, ping pong coding' (and maybe something else). By this time, for sure, I was completely beat. My brain stopped working around 2:30PM and so to be honest it's quite possible that the constraints I listed may be out of order, wrong, or incomplete. Also, by the end of the day (and quite naturally) we were getting less and less code done, but there was more and more conversation around how we would do the code.
While these constraints may seem random or simply designed to annoy, each session ended with some really good discussion as to how these constraints actually make our code more testable, easier to develop (with some practice!) and ultimately better.
Lately I have been reflecting on my time at university. "Youth is wasted on the young", they say, and I believe, sometimes, that "university is wasted on the uneducated". The more I have been able to think about what I learned there, it seems, the more it is that I'm relearning all of these lessons again.
And that's a good thing.
I've also been reminded that I need to extend my knowledge of languages again!
Thanks especially to the City of Summerside for giving us the venue (and gigabit internet to boot!) and all of the organisers (especially Steven Baker and Derek Campbell).
I can't wait for the next one!
Showing posts with label php. Show all posts
Showing posts with label php. Show all posts
Sunday, December 15, 2013
Thursday, August 8, 2013
Not Going to NEPHP? Try Pandacodium Instead!
You may or may not have noticed that I'm heading to Boston next weekend for the Northeast PHP conference. You also may or may not have realised there was a little sarcasm in that last sentence.
But what are you going to do? Where are you going to be? What if I told you that you could attend a hackathon instead?
Well?
Pandacodium is an online, world-wide hackathon that's going to run for 48 hours starting on Friday, August 16th at 7PM.
I don't know if the theme changes every year, but either way, this one is going to be focussed on developing real-time web applications.
Although I've never been to a hackathon, and I'm probably going to miss the one in Charlottetown in a few weeks, it's something that I'm itching to do... and now you all can! Please, let me live through your adventures :)
Seriously: I urge everyone that can to take this opportunity to flex your coding muscle, stretch your comfort zone, meet new people and more importantly have a heap of fun! Head over to http://pandacodium.ca right now and sign up. If I weren't going to Boston, I'd be doing this.
Let me know if you're going to go in it... I want to hear all of the gory details!
But what are you going to do? Where are you going to be? What if I told you that you could attend a hackathon instead?
Well?
Pandacodium is an online, world-wide hackathon that's going to run for 48 hours starting on Friday, August 16th at 7PM.
I don't know if the theme changes every year, but either way, this one is going to be focussed on developing real-time web applications.
Although I've never been to a hackathon, and I'm probably going to miss the one in Charlottetown in a few weeks, it's something that I'm itching to do... and now you all can! Please, let me live through your adventures :)
Seriously: I urge everyone that can to take this opportunity to flex your coding muscle, stretch your comfort zone, meet new people and more importantly have a heap of fun! Head over to http://pandacodium.ca right now and sign up. If I weren't going to Boston, I'd be doing this.
Let me know if you're going to go in it... I want to hear all of the gory details!
Monday, July 29, 2013
NEPHP 2013: Don't Be STUPID, Grasp SOLID
This may be getting boring, but too bad... there are so many talks to see at Northeast PHP this year!
Anthony Ferrara is giving a talk this year titled 'Don't be STUPID, Grasp SOLID' (see http://northeastphp.org/talks/view/33/Don-t-Be-STUPID-Grasp-SOLID and https://joind.in/talk/view/8907).
This is another one of those talks that I think I need to concretely square away some issues I've been having with my code lately. When I first started writing code, I always had small, compact functions. However, somewhere between here and there I lost my way.
I started cramming random meaning into particular function parameters, for example. Depending on the combination of 46 different parameters, the function would do one of 2,500 things... just because it seemed right to use the same function name. This may be because of PHP's lack of function overloading, or it may not. Either way, I realise now how stupid it all was.
Elsewhere, my code started pulling in random static classes, using singletons from static function calls and the like... this is all bad news when you start realising the benefits of unit testing, for example, but in reality, and in my older age, I've realised it's just bad news no matter what.
So like I say: I've started to come back around to smaller functions and classes and already it's made a huge impact on the way I work. I can honestly say that changing that particular approach to my coding has probably saved me more time and given me more safety than any other 'tweak' I've done to my 'style' in the last 5 years. And now that I have a taste for it, I'm looking for more!
Other than the actual topic, I've heard some awesome things about Anthony himself, so it'll be great just to see him talk anyway.
Hopefully you will too!
Anthony Ferrara is giving a talk this year titled 'Don't be STUPID, Grasp SOLID' (see http://northeastphp.org/talks/view/33/Don-t-Be-STUPID-Grasp-SOLID and https://joind.in/talk/view/8907).
This is another one of those talks that I think I need to concretely square away some issues I've been having with my code lately. When I first started writing code, I always had small, compact functions. However, somewhere between here and there I lost my way.
I started cramming random meaning into particular function parameters, for example. Depending on the combination of 46 different parameters, the function would do one of 2,500 things... just because it seemed right to use the same function name. This may be because of PHP's lack of function overloading, or it may not. Either way, I realise now how stupid it all was.
Elsewhere, my code started pulling in random static classes, using singletons from static function calls and the like... this is all bad news when you start realising the benefits of unit testing, for example, but in reality, and in my older age, I've realised it's just bad news no matter what.
So like I say: I've started to come back around to smaller functions and classes and already it's made a huge impact on the way I work. I can honestly say that changing that particular approach to my coding has probably saved me more time and given me more safety than any other 'tweak' I've done to my 'style' in the last 5 years. And now that I have a taste for it, I'm looking for more!
Other than the actual topic, I've heard some awesome things about Anthony himself, so it'll be great just to see him talk anyway.
Hopefully you will too!
Saturday, July 27, 2013
NEPHP 2013: You Can UX Too: Avoiding the Programmer's User Interface
Just another talk I want to see in Boston this year at Northeast PHP 2013...
This talk is on a track that I must admit, I know pretty much nothing about. And to be honest, until recently I've tried to avoid it. But no longer! User Experience (UX) is definitely something I need to be on top of and conferences, talks and workshops are a perfect way to get on the way.
With this in mind, I'm looking forward to the talk 'You Can UX Too: Avoiding the Programmer's User Interface', to be given by Eryn O'Neil. If you want details, check out either http://northeastphp.org/talks/view/187/You-Can-UX-Too-Avoiding-the-Programmer-s-User-Interface or http://joind.in/talk/view/8931.
The reason this is going to be on the top of my 'UX exposure list' is specifically because it speaks directly to me. I am a programmer, no doubt about it, and this talk is addressing the simple (and dare I say obvious?) fact that UX is a problem for programmers. I'm really looking forward to getting an idea of how to take off my coding hat and stick on my UX hat easily, and hopefully more often.
For what it's worth, I'm not saying that I don't want to see any of the other UX talks. On the contrary, this whole realm of software is completely foreign to me and I really need to correct that.
And dare I give kudos to the conference itself for making sure to include this UX track? It's going to be fantastic to have such a wide audience at the one place... I'm looking forward to getting to talk to these 'UX-aware' attendees and finally being able to get an idea of how it all works.
Thursday, July 25, 2013
NEPHP 2013: Agile in the Workplace
So another talk I'm looking forward to seeing this year at Northeast PHP is 'Agile in the Workplace', to be given by Michael Stowe (more details at http://northeastphp.org/talks/view/57/Agile-in-the-Workplace and https://joind.in/talk/view/8914).
To understand why I'm going to find this talk interesting, you have to know that I tend to be one of those people that learns way more through practical examples than I ever do through theory.
The concepts intrigue me, however all the reading in the world is not going to make it all fall together without real life exposure. Unfortunately that would mean finding and working with a group that practices agile correctly... which is not really an option for me. So instead, I'll take the second best thing: I'm going to listen to someone talking about it, and no doubt listen to stories about practical examples.
I'm looking forward to hearing the good and the bad about the process, and ways that I can avoid following those bad practices. For what it's worth, the reason I highlighted the word 'correctly' above is because from what I understand, 'agile' can very easily be a word that gets thrown around by groups, without actually being agile. Every story I've heard about these groups tends to imply that there is a very painful lesson to be learned about the difference between being agile and thinking you're being agile.
Hopefully, too, there may be a way to correctly ease a team into an agile workflow, which I believe would help everyone by being an evolution as opposed to a revolution.
Either way, I say 'viva la agile'. Or something like that... My French is not so good.
To understand why I'm going to find this talk interesting, you have to know that I tend to be one of those people that learns way more through practical examples than I ever do through theory.
The concepts intrigue me, however all the reading in the world is not going to make it all fall together without real life exposure. Unfortunately that would mean finding and working with a group that practices agile correctly... which is not really an option for me. So instead, I'll take the second best thing: I'm going to listen to someone talking about it, and no doubt listen to stories about practical examples.
I'm looking forward to hearing the good and the bad about the process, and ways that I can avoid following those bad practices. For what it's worth, the reason I highlighted the word 'correctly' above is because from what I understand, 'agile' can very easily be a word that gets thrown around by groups, without actually being agile. Every story I've heard about these groups tends to imply that there is a very painful lesson to be learned about the difference between being agile and thinking you're being agile.
Hopefully, too, there may be a way to correctly ease a team into an agile workflow, which I believe would help everyone by being an evolution as opposed to a revolution.
Either way, I say 'viva la agile'. Or something like that... My French is not so good.
Monday, July 22, 2013
NEPHP 2013 Talks: How To Get There
Just another post, keeping hungry for the Northeast PHP conference this coming August in Boston...
What I could only assume is due to the alignment of a number of stars, I see that Larry Ullman is giving a talk titled 'How To Get There' (more details at http://northeastphp.org/talks/view/148/How-To-Get-There and https://joind.in/talk/view/8911).
Lately I have been feeling more and more like I'm not at my peak. I should be better, bigger and more valuable than I am. This is hopefully going to be one of those talks that slaps me in the face and gets me to wake up and push through.
The funny thing about these motivational talks, I find, is the fact that simply by me acknowledging that I want to see this talk pushes me further. Which is awesome.
Even still, I really can't way to see Larry talk. Along with his other talks 'Ajax: You Can Do It Too' and 'Teaching PHP & Web Development' I foresee a day when Larry may have his own track at NEPHP and to be honest, I'd probably end up seeing all of it!
What I could only assume is due to the alignment of a number of stars, I see that Larry Ullman is giving a talk titled 'How To Get There' (more details at http://northeastphp.org/talks/view/148/How-To-Get-There and https://joind.in/talk/view/8911).
Lately I have been feeling more and more like I'm not at my peak. I should be better, bigger and more valuable than I am. This is hopefully going to be one of those talks that slaps me in the face and gets me to wake up and push through.
The funny thing about these motivational talks, I find, is the fact that simply by me acknowledging that I want to see this talk pushes me further. Which is awesome.
Even still, I really can't way to see Larry talk. Along with his other talks 'Ajax: You Can Do It Too' and 'Teaching PHP & Web Development' I foresee a day when Larry may have his own track at NEPHP and to be honest, I'd probably end up seeing all of it!
Thursday, July 18, 2013
NEPHP 2013 Talks: Package Management in PHP
The Northeast PHP Conference is coming up, and to keep myself motivated and on the edge of my seat, I figured I might write about some of the talks and workshops I'm looking forward to...
One of the talks that I'm really excited to see at NEPHP is titled "Package Management in PHP: Better Late than Never!" (you can see it at http://northeastphp.org/talks/view/21/Package-Management-in-PHP-Better-Late-than-Never and https://joind.in/talk/view/8903).
To be honest, I don't think I have to say much on this at all. As far as I'm concerned, if you don't understand the premise then that's a great sign that you have something interesting to look into. If you do understand it and don't care, then I believe that you're on the wrong path.
The description itself explains the crux of the issue: a lot of current (and some not so current) languages already have similar tools for managing the packages that you use in your code, and it's great to see some advancements in this field for PHP.
Don't get me wrong: PEAR was a pretty good start, but it seems as though every attempt at improving that process seemed to fail, until now with Composer and Packagist.
A simple command line tool that lets you easily dictate the required versions of libraries and then takes care of grabbing them (and their dependencies!), storing them in your project and even managing upgrades? Count me in!
While on the one hand we have Composer, that manages these packages, it has to get them from somewhere, and while it can get them from practically anywhere, we look to the other hand and we find Packagist. Packagist is quickly becoming the 'go to' place for these libraries. It's almost like the new PEAR site, or Perl's CPAN. So put these two together and suddenly we have an easy way to find packages, and then an easy way to manage them in our own projects.
It's becoming more and more obvious that we will be using more and more of these focussed packages for single purposes as time goes by, and keeping track of all of that will be a nightmare without something like this. If you're not at least trying to use these packages, then let's face it: you're probably wasting time re-inventing the wheel.
As I mentioned earlier, Composer really is picking up steam and I'm loving the fact that frameworks such as Symfony 2 (and it's little brother Silex) are using it as the go to system for managing their own packages.
I hope I sound as excited as I actually am for this stuff: it's an awesome development for successful code reuse that's spreading across entirely separate projects and all of a sudden PHP developers are OK with reaching outside of their own source tree to find something that works well and works now.
Hat's off to the Composer and Packagist teams, and I can't wait to see Sequoia McDowell's talk at Northeast PHP this year.
Hopefully I'll see you there too!
One of the talks that I'm really excited to see at NEPHP is titled "Package Management in PHP: Better Late than Never!" (you can see it at http://northeastphp.org/talks/view/21/Package-Management-in-PHP-Better-Late-than-Never and https://joind.in/talk/view/8903).
To be honest, I don't think I have to say much on this at all. As far as I'm concerned, if you don't understand the premise then that's a great sign that you have something interesting to look into. If you do understand it and don't care, then I believe that you're on the wrong path.
The description itself explains the crux of the issue: a lot of current (and some not so current) languages already have similar tools for managing the packages that you use in your code, and it's great to see some advancements in this field for PHP.
Don't get me wrong: PEAR was a pretty good start, but it seems as though every attempt at improving that process seemed to fail, until now with Composer and Packagist.
A simple command line tool that lets you easily dictate the required versions of libraries and then takes care of grabbing them (and their dependencies!), storing them in your project and even managing upgrades? Count me in!
While on the one hand we have Composer, that manages these packages, it has to get them from somewhere, and while it can get them from practically anywhere, we look to the other hand and we find Packagist. Packagist is quickly becoming the 'go to' place for these libraries. It's almost like the new PEAR site, or Perl's CPAN. So put these two together and suddenly we have an easy way to find packages, and then an easy way to manage them in our own projects.
It's becoming more and more obvious that we will be using more and more of these focussed packages for single purposes as time goes by, and keeping track of all of that will be a nightmare without something like this. If you're not at least trying to use these packages, then let's face it: you're probably wasting time re-inventing the wheel.
As I mentioned earlier, Composer really is picking up steam and I'm loving the fact that frameworks such as Symfony 2 (and it's little brother Silex) are using it as the go to system for managing their own packages.
I hope I sound as excited as I actually am for this stuff: it's an awesome development for successful code reuse that's spreading across entirely separate projects and all of a sudden PHP developers are OK with reaching outside of their own source tree to find something that works well and works now.
Hat's off to the Composer and Packagist teams, and I can't wait to see Sequoia McDowell's talk at Northeast PHP this year.
Hopefully I'll see you there too!
Monday, June 24, 2013
Northeast PHP Conference 2013
This is me, telling anyone who cares that the Northeast PHP Conference is set to run again this year from August 16-18.
This year is a little different, though, in that as well as the two days of talks, there's also a day of workshops. The line up for speakers is looking awesome and as a way of testing my typing fingers, I'll probably start writing about which talks I'm most interested in... just to keep myself excited :)
The thing I love about this conference is that it has a focus on inclusion: the talks are ranging from beginners to advanced, and there is an entire track dedicated to User Experience, which I think is sorely lacking in our industry.
If anyone else is going to be in Boston for the conference let me know, as I think it'll be an awesome opportunity to catch up or meet for the first time!
This year is a little different, though, in that as well as the two days of talks, there's also a day of workshops. The line up for speakers is looking awesome and as a way of testing my typing fingers, I'll probably start writing about which talks I'm most interested in... just to keep myself excited :)
The thing I love about this conference is that it has a focus on inclusion: the talks are ranging from beginners to advanced, and there is an entire track dedicated to User Experience, which I think is sorely lacking in our industry.
If anyone else is going to be in Boston for the conference let me know, as I think it'll be an awesome opportunity to catch up or meet for the first time!
Monday, December 17, 2012
On Using Javascript to Block Spam... Or Not
A while into one of my previous positions, I was reviewing some of the code behind our main web site, all hand coded by one of my colleagues.
As I came to the contact us form, I noticed the typical spam blocking technique of asking the user to do a small mathematical equation... you know, the normal "What's 2 + 5?" type question.
Interestingly, the form's submit button was not enabled to begin with. As soon as the equation was answered correctly, however, the button became active and the user could submit the form.
Taking a quick look at the code in the browser, it was obvious that this form was entirely using JS to 'enforce' the spam protection. That is to say, JS was required to enable the submit button, and there was no actual server side validation of the spam protection.
Knowing that this is really not the way to do this at all, I asked the developer about it. His answer was that "of course it works... we haven't been getting spammed, have we?"
The answer reminded me very much of Homer Simpson buying Lisa's tiger repelling rock.
Anyway, I tried to make headway with the developer, trying to discuss bots not usually running JS, and so on, but it made no sense to them... as far as they were concerned, it worked as expected.
I finally realised I was just hitting my head against a brick wall and continued with the rest of my work. It was true, we weren't being spammed, and if worse came to worst I could resolve it quickly myself if ever we began to be spammed.
The developer left us not long after, but it was before another colleague and I discovered Google's Skipfish. Without thinking too critically (though we were sure to make sure we weren't going to try anything destructive!) we set it on the site. Things were going really well, until it found our contact us form... and hit it with 100s of different tests. That was the day that we found out that the contact us form also did something else interesting: it sent the email to about a dozen different staff members. By the time it was stopped, I think they each got around 1000 emails, which was really embarrassing.
But at least, I guess, we weren't attacked by any tigers.
As I came to the contact us form, I noticed the typical spam blocking technique of asking the user to do a small mathematical equation... you know, the normal "What's 2 + 5?" type question.
Interestingly, the form's submit button was not enabled to begin with. As soon as the equation was answered correctly, however, the button became active and the user could submit the form.
Taking a quick look at the code in the browser, it was obvious that this form was entirely using JS to 'enforce' the spam protection. That is to say, JS was required to enable the submit button, and there was no actual server side validation of the spam protection.
Knowing that this is really not the way to do this at all, I asked the developer about it. His answer was that "of course it works... we haven't been getting spammed, have we?"
The answer reminded me very much of Homer Simpson buying Lisa's tiger repelling rock.
Anyway, I tried to make headway with the developer, trying to discuss bots not usually running JS, and so on, but it made no sense to them... as far as they were concerned, it worked as expected.
I finally realised I was just hitting my head against a brick wall and continued with the rest of my work. It was true, we weren't being spammed, and if worse came to worst I could resolve it quickly myself if ever we began to be spammed.
The developer left us not long after, but it was before another colleague and I discovered Google's Skipfish. Without thinking too critically (though we were sure to make sure we weren't going to try anything destructive!) we set it on the site. Things were going really well, until it found our contact us form... and hit it with 100s of different tests. That was the day that we found out that the contact us form also did something else interesting: it sent the email to about a dozen different staff members. By the time it was stopped, I think they each got around 1000 emails, which was really embarrassing.
But at least, I guess, we weren't attacked by any tigers.
Sunday, January 29, 2012
Simple Cachebusting for JS
Browsers caching your assets is a good thing. It not only reduces the bandwidth requirements of your site, but it also speeds up loading on the client side every time they visit.
But what happens when you have some changes that you need pushed everywhere to have the site still working? The big thing I'm thinking of here is Javascript. You change the HTML format of a page and all of a sudden your jQuery fails, or your AJAX responses have been tweaked and now your 'onSuccess' functions that work with that data need to be changed... and if they're not, then things don't work.
So what do you do? Of course, there's always the option to stop caching: but that will increase server load, used bandwidth and slow down the loading on the client side. Even if you do disable caching, you're still at the mercy of the client... maybe the browser decides to ignore your cache control requests (or possibly the proxies between the client and the server ignore the requests).
So in trying to work this out, I realised that by adding a random GET parameter will help resolve this issue. Every browser that I have tested against treats the (partial) URL of "random.js?12345" as entirely different from "random.js?12346" as far as caching is concerned, and with good reason. The GET parameter is used for exactly that: to "get" a given resource. It's understandable that the browser would treat these two things as different.
I could use a random number every time to force the cache busting, but that basically sends me back to losing any benefit of browser caching. So the question becomes, what do I use for the GET parameter? Initially I considered using a version number. Every time I changed the JS file, I would change the URL that the generated HTML would use... it would go from "random.js?1.2.3" to "random.js?1.2.4" and so on. In thinking about that implementation, though, I realised that my laziness and forgetfulness would be a deal breaker here as there is no way I would be able to remember to update the URL in (every?) file that references the JS file.
What I ended up doing was actually pretty simple. Every time I include a JS file in the HTML generated by a PHP script, I first quickly find the last modified time of the file and I then append that modified timestamp to the URL.
For my random.js example above, I would do something like the following in my index.php file:
$stats = stat(dirname(__FILE__) . '/random.js');
echo '<script src="random.js?' . $stats['mtime'] . '"/>';
Really simple, perfectly functional and highly cross platform, which is something I always strive to do. If you're not using PHP, then the concept is still the same... you would just need to translate it to your favourite programming language.
Now, if you have a lot of resources that you want to include, maybe you would write a function to try and remove the redundancy, but generally when I do this I only have one or two files to process anyway.
Naturally, the better alternative is to use a framework that does this all for you anyway. A lot of those frameworks do a lot more for you than just the cache busting, so of course they're worth the effort, but if you're not in a situation where you can choose this route, then hopefully the above will help!
But what happens when you have some changes that you need pushed everywhere to have the site still working? The big thing I'm thinking of here is Javascript. You change the HTML format of a page and all of a sudden your jQuery fails, or your AJAX responses have been tweaked and now your 'onSuccess' functions that work with that data need to be changed... and if they're not, then things don't work.
So what do you do? Of course, there's always the option to stop caching: but that will increase server load, used bandwidth and slow down the loading on the client side. Even if you do disable caching, you're still at the mercy of the client... maybe the browser decides to ignore your cache control requests (or possibly the proxies between the client and the server ignore the requests).
So in trying to work this out, I realised that by adding a random GET parameter will help resolve this issue. Every browser that I have tested against treats the (partial) URL of "random.js?12345" as entirely different from "random.js?12346" as far as caching is concerned, and with good reason. The GET parameter is used for exactly that: to "get" a given resource. It's understandable that the browser would treat these two things as different.
I could use a random number every time to force the cache busting, but that basically sends me back to losing any benefit of browser caching. So the question becomes, what do I use for the GET parameter? Initially I considered using a version number. Every time I changed the JS file, I would change the URL that the generated HTML would use... it would go from "random.js?1.2.3" to "random.js?1.2.4" and so on. In thinking about that implementation, though, I realised that my laziness and forgetfulness would be a deal breaker here as there is no way I would be able to remember to update the URL in (every?) file that references the JS file.
What I ended up doing was actually pretty simple. Every time I include a JS file in the HTML generated by a PHP script, I first quickly find the last modified time of the file and I then append that modified timestamp to the URL.
For my random.js example above, I would do something like the following in my index.php file:
$stats = stat(dirname(__FILE__) . '/random.js');
echo '<script src="random.js?' . $stats['mtime'] . '"/>';
Really simple, perfectly functional and highly cross platform, which is something I always strive to do. If you're not using PHP, then the concept is still the same... you would just need to translate it to your favourite programming language.
Now, if you have a lot of resources that you want to include, maybe you would write a function to try and remove the redundancy, but generally when I do this I only have one or two files to process anyway.
Naturally, the better alternative is to use a framework that does this all for you anyway. A lot of those frameworks do a lot more for you than just the cache busting, so of course they're worth the effort, but if you're not in a situation where you can choose this route, then hopefully the above will help!
Monday, January 16, 2012
Will the PHP Community Ever Drop the "Silly n00b" Presumption?
A long, long time ago, I learned my first scripting language: Perl. Admittedly, I wasn't doing any database interactions and to be honest the code wasn't entirely complex (it was a basic user management system with access to different data sets depending on account information).
I wouldn't say that I asked a lot of questions, but I definitely *read* a lot of them and not once can I remember anyone basically answering a question by just pointing out an insecurity in the original posters' question.
Cut now to my current web language of choice: PHP. It seems as though more often than not, one of the first answers to a question online is pointing out the security issues with the question, and a lot of the time, the original question isn't even being answered!
Time and time again, "SQL injection!" or some such stuff is the answer, even when the question had nothing to do with it. It's repetitive and to be completely honest, a little boring now. I almost feel as though Person A got hit with one of these replies once and so now they feel as though they have to pass on the 'love' to Person B.
I don't know what it is that's causing this... there's just too many variables. Is it just a sign of the times? I don't know: I don't spend much time in other language support fields. Is it just because I wasn't aware of these types of replies before? Again, I don't know. Maybe it's just me being a cranky old man looking back on the good old days. Maybe, too, Perl went through these growing pains and I was just fortunate enough to be on the other side of them.
I will go out on a limb, though, and guess it's a combination of two things: 1) the gamification of questions and answers; and 2) the increase in people teaching themselves to code.
Not that either of these things are a problem in and of themselves. Having said that, sites like stackoverflow.com have really made it worthwhile to try and get in and get some upvotes and I hate to say it, but the PHP section of that site is looking less and less usable to me every day. At the same time, more and more people are learning to code in a 'non-professional' environment. Again, this isn't a bad thing, however I get the feeling that these basic security issues seem to have been missed the first time over when people teach themselves so to them, it's amazingly impressive to be able to find these issues with someone elses code, to the point where the answer to the actual question doesn't matter as much as this.
Maybe I'm just tired, but I just feel as though at some point, the PHP community as a whole needs to get over this whole thing about "commenting on security problems is my number one concern, even if I can't answer the original question"... it just isn't helping anyone.
Don't get me wrong: a good, correct answer is fantastic, even if there's an aside of "BTW, SQL injection!" but please, that's not always the answer!
I wouldn't say that I asked a lot of questions, but I definitely *read* a lot of them and not once can I remember anyone basically answering a question by just pointing out an insecurity in the original posters' question.
Cut now to my current web language of choice: PHP. It seems as though more often than not, one of the first answers to a question online is pointing out the security issues with the question, and a lot of the time, the original question isn't even being answered!
Time and time again, "SQL injection!" or some such stuff is the answer, even when the question had nothing to do with it. It's repetitive and to be completely honest, a little boring now. I almost feel as though Person A got hit with one of these replies once and so now they feel as though they have to pass on the 'love' to Person B.
I don't know what it is that's causing this... there's just too many variables. Is it just a sign of the times? I don't know: I don't spend much time in other language support fields. Is it just because I wasn't aware of these types of replies before? Again, I don't know. Maybe it's just me being a cranky old man looking back on the good old days. Maybe, too, Perl went through these growing pains and I was just fortunate enough to be on the other side of them.
I will go out on a limb, though, and guess it's a combination of two things: 1) the gamification of questions and answers; and 2) the increase in people teaching themselves to code.
Not that either of these things are a problem in and of themselves. Having said that, sites like stackoverflow.com have really made it worthwhile to try and get in and get some upvotes and I hate to say it, but the PHP section of that site is looking less and less usable to me every day. At the same time, more and more people are learning to code in a 'non-professional' environment. Again, this isn't a bad thing, however I get the feeling that these basic security issues seem to have been missed the first time over when people teach themselves so to them, it's amazingly impressive to be able to find these issues with someone elses code, to the point where the answer to the actual question doesn't matter as much as this.
Maybe I'm just tired, but I just feel as though at some point, the PHP community as a whole needs to get over this whole thing about "commenting on security problems is my number one concern, even if I can't answer the original question"... it just isn't helping anyone.
Don't get me wrong: a good, correct answer is fantastic, even if there's an aside of "BTW, SQL injection!" but please, that's not always the answer!
Tuesday, October 19, 2010
Static Analysis with PHP CodeSniffer
PHP CodeSniffer is a great tool to have in your development
environment. Originally developed to ensure that your code matches your
coding standards, I think its strength is somewhere else...
If you take the time to read through some of the coding standards that ship with PHP CodeSniffer, you will find that some of them don't really relate to coding standards exactly. Some are more related to code analysis, and after a recent update to a project I was working on, I think that this is PHP CodeSniffer's real strength...
You may recall from an earlier post that one of the projects I was working on used an in house DB abstraction layer. For reasons that are probably obvious, we began porting our code to MDB2. It was a large codebase, with queries sprinkled throughout. Quickly we realised that search and replace was not going to cut it, as we needed to begin using a result set variable.
The original class used a single variable for the connection and the result set. That is to say, with the single variable you would connect to the database, make the query and then iterate over the result set. MDB2 is different (and in this regard, more like the basic MySQL functions in PHP) in that you have one variable for the connection, call the query on that connection and then store the return value into another variable (the result set). So in effect, you use one variable for some things (calling queries, getting error messages and so on) and another for iterating over the results. Our problem with porting was that our class used one variable for all of that, so we couldn't easily search and replace.
So what to do? Well naturally we could have looked everywhere for any instance where we made a connection, then ensured that the variable was used correctly, as were any variables returned from function calls. Or, we could have automated it.
So automate it I did.
I had been playing with PHP CodeSniffer anyway, and so I saw a great use for it here. Of course, it's really the tokeniser that we're taking advantage of, but PHPCS does a great job of providing us with extra features related to moving through the token list.
A couple of hours later, I had written the sniff. But what does it do? Well basically it looks for function calls that make a connection to the database. When it finds that, it looks back a little bit and determines the variable name that was being assigned to. We now know a variable that holds a DB connection, and with a little bit more magic, we can determine the scope that this variable is used in. Now look around in that scope, and ensure that when that variable gets used, it gets used in the right context. Let's go a bit deeper though... if the connection gets used in the right function, we know that the return value is a result set. Surely we can then iterate through it, doing the same work, testing that it gets used correctly?
And that's what I did. Because we were using MDB2, I even had more information... using reflection, I was able to determine return types of all sorts of functions and functions that existed on all sorts of classes. I could make sure that those variables were used correctly and that any functions called on those variables were valid for their class.
It was great, even if I do say so myself! In a couple of hours, I was able to test our entire codebase and ensure, recursively, that all of the variables that we were assigning to, passing as parameters, and calling functions on were being used in the right context.
And we found a heap of places where our attempts at porting went wrong. Which is what it's all about.
After that, I went nuts with static analysis. I started looking even at the queries that were being called and checking that when doing a SELECT COUNT, for example, that we used the queryOne function to just grab the value instead of returning it into an array to simply pull it out from $row[0].
I also wrote another sniff that ensured that when using references in a foreach loop, that we unset the by-reference variable before reusing it (so as to make sure we didn't accidentally overwrite part of the initial array).
I think using PHP CodeSniffer this way is awesome. It takes care of so much stuff and when adding in reflection on classes it's amazing what can be achieved in just a few lines of code.
I'd love to hear if you have ever solved a static analysis problem with PHP CodeSniffer!
If you take the time to read through some of the coding standards that ship with PHP CodeSniffer, you will find that some of them don't really relate to coding standards exactly. Some are more related to code analysis, and after a recent update to a project I was working on, I think that this is PHP CodeSniffer's real strength...
You may recall from an earlier post that one of the projects I was working on used an in house DB abstraction layer. For reasons that are probably obvious, we began porting our code to MDB2. It was a large codebase, with queries sprinkled throughout. Quickly we realised that search and replace was not going to cut it, as we needed to begin using a result set variable.
The original class used a single variable for the connection and the result set. That is to say, with the single variable you would connect to the database, make the query and then iterate over the result set. MDB2 is different (and in this regard, more like the basic MySQL functions in PHP) in that you have one variable for the connection, call the query on that connection and then store the return value into another variable (the result set). So in effect, you use one variable for some things (calling queries, getting error messages and so on) and another for iterating over the results. Our problem with porting was that our class used one variable for all of that, so we couldn't easily search and replace.
So what to do? Well naturally we could have looked everywhere for any instance where we made a connection, then ensured that the variable was used correctly, as were any variables returned from function calls. Or, we could have automated it.
So automate it I did.
I had been playing with PHP CodeSniffer anyway, and so I saw a great use for it here. Of course, it's really the tokeniser that we're taking advantage of, but PHPCS does a great job of providing us with extra features related to moving through the token list.
A couple of hours later, I had written the sniff. But what does it do? Well basically it looks for function calls that make a connection to the database. When it finds that, it looks back a little bit and determines the variable name that was being assigned to. We now know a variable that holds a DB connection, and with a little bit more magic, we can determine the scope that this variable is used in. Now look around in that scope, and ensure that when that variable gets used, it gets used in the right context. Let's go a bit deeper though... if the connection gets used in the right function, we know that the return value is a result set. Surely we can then iterate through it, doing the same work, testing that it gets used correctly?
And that's what I did. Because we were using MDB2, I even had more information... using reflection, I was able to determine return types of all sorts of functions and functions that existed on all sorts of classes. I could make sure that those variables were used correctly and that any functions called on those variables were valid for their class.
It was great, even if I do say so myself! In a couple of hours, I was able to test our entire codebase and ensure, recursively, that all of the variables that we were assigning to, passing as parameters, and calling functions on were being used in the right context.
And we found a heap of places where our attempts at porting went wrong. Which is what it's all about.
After that, I went nuts with static analysis. I started looking even at the queries that were being called and checking that when doing a SELECT COUNT, for example, that we used the queryOne function to just grab the value instead of returning it into an array to simply pull it out from $row[0].
I also wrote another sniff that ensured that when using references in a foreach loop, that we unset the by-reference variable before reusing it (so as to make sure we didn't accidentally overwrite part of the initial array).
I think using PHP CodeSniffer this way is awesome. It takes care of so much stuff and when adding in reflection on classes it's amazing what can be achieved in just a few lines of code.
I'd love to hear if you have ever solved a static analysis problem with PHP CodeSniffer!
Tuesday, November 17, 2009
Iterating with mysql_data_seek()
Looking back, it makes sense... but I've only just realised that the mysql_data_seek() function can be a real drag on your code.
Sometimes things just hit you like a brick: this happened to me just recently while looking through some code. Before I go too far, though, maybe a little back story is necessary.
There comes a time, it seems, that every PHP developer wants to write a DB access class. It almost seems to be a right of passage: everyone codes one and eventually ends up using another library written by someone else.
I was working on a piece of code that used such a class. For the longest time, this class worked well. It worked across a number of projects and became one of those "pieces of code that you just use all the time". In a relatively intense piece of code, we were butting up against a pretty heavy time cost: we were looping through a little over 100,000 rows, but this loop was taking around 15 minutes to complete.
We looked to make sure there was nothing wrong with the inner workings of the loop. Were we doing some other loop inside it, even accidentally? Maybe there was a function call that was taking a long time to complete? We worked through each possibility, ignoring the way we were actually grabbing the data.
The way we would grab the data is similar to what (I believe) a lot of other, homegrown access classes does: pass in a row number, seek to that row and fetch the result. This would let us skip rows, short circuit out of a loop or jump results more easily if the PHP logic needed it. The way we would loop over it would be to get a row count at the start then do a typical, for ($i = 0; ($i < $row_count); $i++) loop, calling a GetDataRow($i) within the loop. As I mentioned earlier, GetDataRow($i) would call mysql_data_seek($i) then mysql_fetch_assoc().
As we drilled down into our code, we started to realise our problem: things were just taking longer and longer to process, the further into the row count we went. This is probably why we never noticed anything: we had just never called this function on such a large result set.
Just to be sure, I tried starting the loop with $i equal to 50,000. The loop ran a bit quicker, but still that last 50,000 took a lot longer than the first 50,000. We had found our problem.
But what to do?
I did the same thing any sane PHP developer would do: hit the documentation at php.net. One, maybe two minutes later, I had all the data I needed to at least test something. It turns out that mysql_fetch_assoc() automatically moves the row pointer ahead one. Instead of explicitly calling the mysql_data_seek($i) for each $i, we only needed to continually call mysql_fetch_assoc() until it returned false.
While I found that interesting I couldn't see why this would be a problem. I mean surely the mysql_data_seek call would have a pretty good Big-O implementation... especially if we were meant to just be seeking to the row we were already on!
Unfortunately the data proved otherwise. Eventually it became obvious that in reality, we have a resource totally separated from the PHP process itself: there is no real way for us to just jump into a particular row.
So what kind of increase in performance did we see? To our absolute dismay, the 15 minute loop completed in approximately 4.5 seconds.
I know that that sounds incredible, but it's true. I've attached some code that should help to prove my point. If, however, you'd rather just see the numbers for yourself, they're here, too :)
Let me explain the numbers in the following table: we iterate through 100,000 rows, so l only show times for every 10,000 rows. Each number in the table is a count in seconds, from the start. That is to say, the number at the 30,000 row point is how long it took to get to those 30,000 rows. To see how long it took to get from one row to the next, you can see the number with the plus sign. The three different counts we do represent the three different tests we ran. "Iterating" is the time it took to get through the rows, without running mysql_data_seek for each row. "Seeking" is what happened when we did call mysql_data_seek and "Seeking (starting at 50000)" is, unsurprisingly, the times it took when calling mysql_data_seek, but starting at 50,000 rows. This test was run to see if the time was related to how many times we had called mysql_data_seek, or if it was related to which row number we were actually seeking to. As you can see, it's the latter.
If you're more of a visual person, here's a really basic graph:
For what it's worth, yes, the "Iterating" line is essentially flat. That's because of how much faster it was.
If you'd like to test this yourself, I've uploaded some code to http://files.codefromaway.net/mysql_data_seek.tar.gz : it can prepare some random data for you then run the tests so that you can compare the numbers yourself.
So that's that, and that's why I don't think I'll ever stop learning: it doesn't matter what you take for granted, some things will always work differently to what you expect...
Sometimes things just hit you like a brick: this happened to me just recently while looking through some code. Before I go too far, though, maybe a little back story is necessary.
There comes a time, it seems, that every PHP developer wants to write a DB access class. It almost seems to be a right of passage: everyone codes one and eventually ends up using another library written by someone else.
I was working on a piece of code that used such a class. For the longest time, this class worked well. It worked across a number of projects and became one of those "pieces of code that you just use all the time". In a relatively intense piece of code, we were butting up against a pretty heavy time cost: we were looping through a little over 100,000 rows, but this loop was taking around 15 minutes to complete.
We looked to make sure there was nothing wrong with the inner workings of the loop. Were we doing some other loop inside it, even accidentally? Maybe there was a function call that was taking a long time to complete? We worked through each possibility, ignoring the way we were actually grabbing the data.
The way we would grab the data is similar to what (I believe) a lot of other, homegrown access classes does: pass in a row number, seek to that row and fetch the result. This would let us skip rows, short circuit out of a loop or jump results more easily if the PHP logic needed it. The way we would loop over it would be to get a row count at the start then do a typical, for ($i = 0; ($i < $row_count); $i++) loop, calling a GetDataRow($i) within the loop. As I mentioned earlier, GetDataRow($i) would call mysql_data_seek($i) then mysql_fetch_assoc().
As we drilled down into our code, we started to realise our problem: things were just taking longer and longer to process, the further into the row count we went. This is probably why we never noticed anything: we had just never called this function on such a large result set.
Just to be sure, I tried starting the loop with $i equal to 50,000. The loop ran a bit quicker, but still that last 50,000 took a lot longer than the first 50,000. We had found our problem.
But what to do?
I did the same thing any sane PHP developer would do: hit the documentation at php.net. One, maybe two minutes later, I had all the data I needed to at least test something. It turns out that mysql_fetch_assoc() automatically moves the row pointer ahead one. Instead of explicitly calling the mysql_data_seek($i) for each $i, we only needed to continually call mysql_fetch_assoc() until it returned false.
While I found that interesting I couldn't see why this would be a problem. I mean surely the mysql_data_seek call would have a pretty good Big-O implementation... especially if we were meant to just be seeking to the row we were already on!
Unfortunately the data proved otherwise. Eventually it became obvious that in reality, we have a resource totally separated from the PHP process itself: there is no real way for us to just jump into a particular row.
So what kind of increase in performance did we see? To our absolute dismay, the 15 minute loop completed in approximately 4.5 seconds.
I know that that sounds incredible, but it's true. I've attached some code that should help to prove my point. If, however, you'd rather just see the numbers for yourself, they're here, too :)
Let me explain the numbers in the following table: we iterate through 100,000 rows, so l only show times for every 10,000 rows. Each number in the table is a count in seconds, from the start. That is to say, the number at the 30,000 row point is how long it took to get to those 30,000 rows. To see how long it took to get from one row to the next, you can see the number with the plus sign. The three different counts we do represent the three different tests we ran. "Iterating" is the time it took to get through the rows, without running mysql_data_seek for each row. "Seeking" is what happened when we did call mysql_data_seek and "Seeking (starting at 50000)" is, unsurprisingly, the times it took when calling mysql_data_seek, but starting at 50,000 rows. This test was run to see if the time was related to how many times we had called mysql_data_seek, or if it was related to which row number we were actually seeking to. As you can see, it's the latter.
| At row number... | Iterating | Seeking | Seeking (starting at 50000) |
| 10000 | 0.029 +0.029 |
0.358 +1.157 |
N/A |
| 20000 | 0.058 +0.029 |
1.514 +3.481 |
N/A |
| 30000 | 0.087 +0.029 |
4.995 +7.563 |
N/A |
| 40000 | 0.116 +0.029 |
12.558 +10.838 |
N/A |
| 50000 | 0.145 +0.029 |
23.396 +12.973 |
N/A +12.445 |
| 60000 | 0.175 +0.031 |
36.369 +14.185 |
12.445 +14.425 |
| 70000 | 0.206 +0.029 |
50.554 +16.671 |
26.869 +17.510 |
| 80000 | 0.235 +0.030 |
67.225 +19.212 |
44.379 +20.559 |
| 90000 | 0.264 +0.030 |
86.437 +21.122 |
64.938 +21.273 |
| 100000 | 0.294 | 107.559 | 86.211 |
If you're more of a visual person, here's a really basic graph:
For what it's worth, yes, the "Iterating" line is essentially flat. That's because of how much faster it was.
If you'd like to test this yourself, I've uploaded some code to http://files.codefromaway.net/mysql_data_seek.tar.gz : it can prepare some random data for you then run the tests so that you can compare the numbers yourself.
So that's that, and that's why I don't think I'll ever stop learning: it doesn't matter what you take for granted, some things will always work differently to what you expect...
Subscribe to:
Posts (Atom)
