<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule">

<channel>
	<title>Pádraic Brady &#187; Irishisms</title>
	<atom:link href="http://blog.astrumfutura.com/category/Irishisms/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.astrumfutura.com</link>
	<description>PHP, Zend Framework and Other Crazy Stuff</description>
	<lastBuildDate>Wed, 25 Jan 2012 11:12:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com"/><creativeCommons:license>http://creativecommons.org/licenses/by-nc-nd/3.0/</creativeCommons:license>		<item>
		<title>Unapologetic To The End? I think Zend_OpenId hates me&#8230; Hates it back!</title>
		<link>http://blog.astrumfutura.com/2009/07/unapologetic-to-the-end-i-think-zend_openid-hates-me-hates-it-back/</link>
		<comments>http://blog.astrumfutura.com/2009/07/unapologetic-to-the-end-i-think-zend_openid-hates-me-hates-it-back/#comments</comments>
		<pubDate>Mon, 27 Jul 2009 00:50:06 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[PHP General]]></category>
		<category><![CDATA[PHP Security]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[irishisms]]></category>
		<category><![CDATA[php general]]></category>
		<category><![CDATA[php security]]></category>
		<category><![CDATA[rantings]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=402</guid>
		<description><![CDATA[Disclaimer: The following is obviously a spur of the moment tirade of sarcastic commentary and lots of (probably bad) humour. A lot of it refers to events from two years ago (that&#8217;s around ZF 0.8!). Ancient history . Mostly. In any case, I have to rant about something once a year related to the Zend]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F07%2Funapologetic-to-the-end-i-think-zend_openid-hates-me-hates-it-back%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F07%2Funapologetic-to-the-end-i-think-zend_openid-hates-me-hates-it-back%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=irishisms,php+general,php+security,rantings,zend+framework&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Disclaimer: The following is obviously a spur of the moment tirade of sarcastic commentary and lots of (probably bad) humour. A lot of it refers to events from two years ago (that&#8217;s around ZF 0.8!). Ancient history <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> . Mostly. In any case, I have to rant about something once a year related to the Zend Framework. It&#8217;s traditional. Park any attempt to take this too seriously at the door. I get a bit dramatic at times&#8230;</p>
<p>In certain places, I do sometimes get a reputation of being a crazy person. Usually it happens shortly after I find myself going down a road that leads somewhere truly undesireable (or when I throw in a weird blog post like this one). I had one of those moments today that served as a flashback to such a point in time from 2007. It&#8217;s not the first time, but it will be the last since I&#8217;ll ignore it completely from now on. Believe it or not, I do get a bit upset at myself when I let these times get to me. They are completely unimportant and silly &#8211; but when I have to relive them I will react in a pretty irritated fashion (ed: that should be kneejerk incendiary fashion).</p>
<p>This one started in 2007, right about the time I was first starting to write proposals for the Zend Framework. I felt pretty great at the time. I had lots of ideas, plenty of motivation, and then it all seemed to go downhill from there. The turning point was in June 2007, when after three months of work I felt I had enough done to propose OpenID support for the framework. Obviously a worthy cause, and also one which shouldn&#8217;t cause much grief since the ZF keeps advertising its wicked web service support. Before long, that boat was scuttled with news that Zend itself had been working on just such a proposal. Okay, that was disappointing. Zend had somehow managed to completely miss a three month effort on OpenID. Just another day on the farm. Next step? Collaborate? So I waited a few days and Zend&#8217;s code for what would become Zend_OpenId appeared in my inbox. Let the review commence! Okay, that ended a bit abruptly&#8230;it&#8217;s a bit short. Almost like it&#8217;s missing stuff and was written in a handful of days as a prototype. Talking went on and off for a while, and eventually my interest in collaborating petered out. Like any open source contributor, I participate to scratch an itch. My OpenID itch was well and truly scratched by now with my own source code, and continuing to throw time at another OpenID solution based on a different paradigm with a different ideology, little of which I agreed with, when I already had one functional was pretty pointless compared to something that still needed scratching like the Zend_View Enhanced proposal (and I really needed that shepherded through). So Zend_OpenId continued without my assistance, with something for Yadis persisting in the Incubator as an orphaned proposal. It still persists waiting that one final patch and call to the trunk&#8230; One day&#8230;</p>
<p>This all sounds reasonable and a bit dry, but in reality I found it all intolerable. A self-professed OpenID expert who is a member of an OpenID Foundation decides to add OpenID support to the Zend Framework after working on it for three months and who has actual code to prove it, is then told about the other proposal which just happens to be coming at the same time, and has code&#8230;of course. Well, a bit of code. If I were a real nut&#8230;I&#8217;d have a field day. Collaborate? I&#8217;d already finished this twice. I&#8217;m supposed to go for round three? Yeah, I admit, I was getting pissed off very quickly back then. I was close to constructing an elaborate conspiracy between Zend, George W. Bush and the Illuminati (how could you NOT have the Illuminati <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ). What was nagging me from the start was the obvious &#8211; I should have told someone to stuff that proposal somewhere and forged ahead with my own. Of course I didn&#8217;t. I was new, and had green stuff growing out of my ears, and it was Zend. The Zend. Silly me&#8230;</p>
<p>The summer of 2007 left me wishing the Zend Framework Proposal Process would shrivel, die and get gobbled down by Orcses (I was hoping for Gollum but he&#8217;s a hotshot movie star now). It remains the single worst open source experience I have had since I joined the open source gig in 1995. Not only was it discouraging, it was demoralising. There were points when I was driven to contemplate whether my input was even wanted. Which is probably why I remain so overly sensitive about it &#8211; I can understand the new guy is immediately suspect. But not like this. In September 2007 I finally wrote the blog post &#8220;<a href="http://blog.astrumfutura.com/archives/308-How-a-proposal-process-could-work-if-retaining-contributors-is-a-goal.html">How a proposal process could work &#8211; if retaining contributors is a goal</a>&#8221; out of frustration. As the title suggested, and others guessed, I was borderline on taking a hike from contributing. Some months later I gave some ground, and <a href="http://blog.astrumfutura.com/archives/339-Zend_Yaml;-Gone-the-way-of-the-Dodo....html">deleted Zend_Yaml as a proposal</a>. Waiting for a review, or challenging non-existent reviews, or noticing the distinct lack of communication between people gets tiresome eventually. I have a spectacular tendency to vanish for months on projects, but not a whole year. Also, using it as a condition when reviewing another proposal was just fucking stupid. After a few bouts of initial enthusiasm, Zend_Service_Yadis joined it for any worthwhile purpose. That is my fault of course &#8211; my motivation to finish a library already released on PEAR had simply evaporated. That scratch your itch thing again &#8211; it was scratched on PEAR already. By now Yadis had been in use for over a year in production in other forms, and Zend_OpenId wasn&#8217;t going anywhere.</p>
<p>Thankfully, since mid-2008, that horrible system seems to have mostly vanished for good. The change in topics may have helped too. Not many people have considered reimplementing Zend_Feed, and for a change, nobody had been busy on any secret OAuth components. It&#8217;s taken roughly a year, but these are finding themselves in the trunk and Incubator respectively and should see ZF 1.9 and ZF 1.10 in turn. Hurrah, I committed actual finished code for once&#8230;;). I&#8217;ve also dropped any pretense at applying Agile methods to proposals. When I propose something, it will have backing code, class skeletons and use cases (basically the entire integration test suite). It won&#8217;t be complete, but it will be sufficiently functional. Overall, I haven&#8217;t been irritated in months (well, before today).</p>
<p>But why, why does the whole Zend_OpenId episode still carry weight? It hit me today, when I was scanning my email and I spotted a note about some Zend Framework libraries showing their age and lack of maintenance. Perfectly normal for something the size of Zend Framework &#8211; code rot is persistent anywhere. It can be difficult to diagnose though unless you are a regular user or the maintainer, so I shot off a reply adding that the same applies to Zend_OpenId. It was only intended as a supportive example, something I&#8217;m personally familiar with since I&#8217;m the guy with &#8220;Zend Framework&#8221; and &#8220;OpenID Europe Foundation Representative&#8221; written all over their email signatures, so apparently this makes me an expert on the topic. I field a lot of questions about Zend_OpenId at times. As anyone using it knows, Zend_OpenId just doesn&#8217;t work at the moment depending on the Provider. It&#8217;s woefully outdated.</p>
<p>However, it appears that&#8230;I am the Zend_OpenId maintainer! Really? Huh? Wait a minute&#8230; WTF?</p>
<p>Que 2007 flashback&#8230; Que obligatory irritated kneejerk response disavowing all alleged responsibility for afore mentioned proposal I have never contributed any code to&#8230; </p>
<p>I know where this started. At some point in 2008 I did agree to look into OpenID 2.0 support. It was one of those goodwill moments, where you know you&#8217;ll get around to it&#8230;eventually&#8230;after A, B, C and probably D. And you really mean it too, until you&#8217;re dragged into someone&#8217;s office and told about E. Then the mysterious Z pops by for a few months with a couple of mates. Anyway&#8230;it never went further. No proposals, no code, no discussions, no nothing. I only vaguely remember the email even. I imagine I forgot about it within a week until I was reminded about it today, and am apparently being held to it by superglue and ISP records of the email (just joking about the ISP records). God help me. Why are you laughing? This is fucking serious!</p>
<p>Now, being the apparent Zend_OpenId maintainer and therefore responsible for all issues filed since Spring/Summer 2008&#8230;I resign, effective immediately. It&#8217;s bad for my heart, and my irritation levels. More so now that I know about it. Now that I have resigned, I can see something of the funny side. If I complain about Zend_OpenId &#8211; it really is all my fault. Even if I was unaware of it. Allegedly.</p>
<p>Seeing a funny side, and having the benefit of hindsight, I can recognise where it all went off the rails back in 2007. Back in 2007 I should have been more of an ass. Yessir, I should done a Hugh Laurie on someone! Instead I retreated into politeness, followed by disinterest. I should have done exactly what I did with Zend_View Enhanced &#8211; write the bloody thing to death in a multi-part monologue that would have directed my legion of rag wearing subjects (er&#8230;readers) to assault the edifice of Zend Technologies Inc. until they caved and decided proper OpenID support was popular enough to warrant some real attention, i.e. raise bloody murder. If nobody listens in private, then shout it from the rooftops. But I didn&#8217;t. And Zend_OpenId is broken. And the OpenID Community is all the poorer for it. So it really truly is all my fault. I wasn&#8217;t a big enough ass. I will try to endeavour to be a bigger asshole in the future. May god have mercy on all your souls.</p>
<p>Now that we&#8217;ve established blame, and didn&#8217;t even need svn to do it (since I&#8217;m not listed there&#8230;aha), can we update a few records? In the maintainer field, right on the table called Zend_OpenId, can we change that to NULL or &#8220;Zend&#8221; since they actually wrote it so presumably are responsible also for its maintenance? While we&#8217;re at it, can we make it a new rule that the ex-proposer of features later proposed by a completely different party, not be held responsible for the completely different party&#8217;s screwups? Thanks.</p>
<p>This years &#8220;Paddy Rants About Something In The Zend Framework You Couldn&#8217;t Care Less About&#8221; was brought to you by&#8230;well&#8230;me.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/07/unapologetic-to-the-end-i-think-zend_openid-hates-me-hates-it-back/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Wrox Press Respond to &#8220;The Art Of Deception Or Publishing PHP6 Books&#8221;</title>
		<link>http://blog.astrumfutura.com/2009/06/wrox-press-respond-to-the-art-of-deception-or-publishing-php6-books/</link>
		<comments>http://blog.astrumfutura.com/2009/06/wrox-press-respond-to-the-art-of-deception-or-publishing-php6-books/#comments</comments>
		<pubDate>Thu, 25 Jun 2009 19:03:28 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[PHP General]]></category>
		<category><![CDATA[PHP Security]]></category>
		<category><![CDATA[irishisms]]></category>
		<category><![CDATA[php general]]></category>
		<category><![CDATA[php security]]></category>
		<category><![CDATA[php6]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=399</guid>
		<description><![CDATA[I am such a torment. Cancelled negotiations with a publisher over disagreements on a book format? Check. Said no to taking down a free book startup and enter a publishing contract? Check. Lambasted multiple publishers for releasing PHP 6 books which do not teach anything PHP 6 specific? Check. Next month I expose which publishing]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F06%2Fwrox-press-respond-to-the-art-of-deception-or-publishing-php6-books%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F06%2Fwrox-press-respond-to-the-art-of-deception-or-publishing-php6-books%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=irishisms,php+general,php+security,php6&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>I am such a torment. Cancelled negotiations with a publisher over disagreements on a book format? Check. Said no to taking down a free book startup and enter a publishing contract? Check. Lambasted multiple publishers for releasing PHP 6 books which do not teach anything PHP 6 specific? Check. Next month I expose which publishing companies are secretly building weapons of mass destruction in their basements. Reverse that, I can&#8217;t afford a libel suit&#8230;</p>
<p>In &#8220;<a href="http://blog.astrumfutura.com/archives/402-The-Art-Of-Deception-Or-Publishing-PHP6-Books.html" >The Art Of Deception Or Publishing PHP6 Books</a>&#8221; I aired my unflattering opinions about publishers who have been selling &#8220;PHP 6&#8243; books. PHP 6, last I checked, was a bit like Leprechauns (Hey, I&#8217;m Irish! The use is legal!). You love them, you have lots of ideas about what to expect from them &#8211; but has anyone every really seen one (other than my great uncle)? PHP 6 exists in CVS &#8211; it&#8217;s never had a release other than the usual CVS snapshots. It&#8217;s certainly not complete and stable, and its future feature list remains a bit flexible. You could see PHP 5.4 in 2011 before PHP 6 is finished&#8230;guessing here. As its developers would say &#8211; it&#8217;ll be ready when it&#8217;s ready. One day. Maybe.</p>
<p>In response to the blog post, Wrox Press picked up on the problem on Twitter via <a href="http://daveyshafik.com" >Davey Shafik</a> (<a href="http://twitter.com/dshafik" >@dshafik</a>). Everyone knows Davey. If you don&#8217;t, you must have been living under a rock, or a ruby, for a really long time. I have to say, Wrox responded in a wholly unpredicted way I have to admire. It&#8217;s not everyday you find yourself hiding in a cave in Antrim (it&#8217;s nice&#8230;a little damp though) after seeing something you wrote persuade a publisher to pull back a book destined for the printers, and work on fixing it so it deserves its title.</p>
<p>Here&#8217;s the full text of the comment posted to &#8220;The Art Of Deception&#8230;&#8221; earlier today by Jim Minatel (Associate Publisher &#8211; Wrox). Jim is mostly the person sitting behind <a href="http://twitter.com/wrox" >@wrox</a> over on Twitter where he&#8217;s been quite proactive in getting to the bottom of my PHP 6 Book complaints.</p>
<blockquote><p>Pádraic:</p>
<p>Thanks for taking the time to discuss this with me on Twitter last night. I’m the Associate Publisher for Wrox, I’m the person usually behind @wrox on twitter.</p>
<p>After meeting with the editor who ran the PHP list for us, you’re right. The titles of these PHP6 books, some of the references to PHP6 in the books, what isn’t covered in the books, all prove we made a mistake, something went wrong. But how, why?</p>
<p>Elizabeth (and thanks for her measured response) is correct in part of her assessment that books take a long time to write and publish. I’m sure that when the editor and authors started these books in Spring 2008, they’re thinking was that 6.0 would indeed be a stable release by early 2009 (if not sooner) and they were aiming for that. But clearly along the way we dropped the ball on checking references to things like the non-existent “6.0.0 stable.”</p>
<p>In the Beginning PHP6, MySQL, Apache book, I can actually understand the rationale not to cover Unicode there. Given that Unicode is primarily valuable to someone internationalizing a site or localizing it for multiple languages – topics that I wouldn’t consider “Beginning” level – I can see why it wasn’t covered. (Before becoming associate publisher, I was actually our ASP.NET editor for most of the last 5 years and we don’t for example cover internationalization/localization in our Beginning ASP.NET 3.5.) So we want to have a book that Beginning level customers understand will work with PHP6 if that’s the version they’re using, but we didn’t communicate right what that meant in this context where there weren’t major new v6 features at the level we thought a beginner would need.</p>
<p>The professional book stumps me more. It’s hard for me to understand how that book doesn’t have a chapter on Unicode. It looks like an oversight by everyone involved in the book.</p>
<p>So where do we go from here and get better than this to eventually prove we’re worthy of better than when @bicatu says “That reminds me why I&#8217;ve never bought a Wrox book?”</p>
<p>First, I’ve asked the team involved with Beginning PHP6 scheduled to ship to the printer this week to pull that book back, to read your post and the subsequent twitter discussion and to make sure we aren’t making the same mistake a third time. I want the author and editors to provide a level of confidence that the PHP6 features that should be covered are, that the discussion of the current state of PHP6 is accurate, and the that the title, subtitle, and marketing copy on the book and online accurately reflects what is and isn’t covered.</p>
<p>Second, publishing the right books depends on having the right team, including a large number of well placed community experts on the topics who serve as authors, freelance/contract technical editors. There’s always room for a team to improve, through learning and through recruiting. I hope this discussion helps our current team in PHP (and MySQL and LAMP in general) and I hope it helps us attract people like you who have ideas on what we can do better. I’d like to invite you and everyone who’s commented on this post so far (and I’ll post the invite on twitter too) to get involved. We’ve got a PHP Design Patterns book scheduled to publish in August (not specific to any version) I’d like to start by offering you all a preview of that. If you see any red flags, tell us. If you like it, if you see issues and help us make it better, at a minimum we’ll send you a free copy. If you get involved more extensively, you can discuss with the editor contract work. DM me in twitter with your email addresses if you want to get involved. Or email me at the address below.</p>
<p>Thanks for caring enough to get our attention. I promise, we’re listening.</p>
<p>Jim Minatel<br />
Associate Publisher – Wrox<br />
jminatel at w I l e y d o t c o m</p></blockquote>
<p>On a side note, Jim spelled my name correctly. Class. I called Jim, &#8220;John&#8221;, on Twitter. Fail.</p>
<p>Rather impressed with Wrox right now.</p>
<p>If I have a remaining concern it would be that with PHP 6 unreleased and in flux, it still seems dangerous to title books using that version number. The most current updated PHP version from next Tuesday will be PHP 5.3 which is itself a pretty giant leap over PHP 5.2. PHP 6 is conceivably years away &#8211; its release date isn&#8217;t set in stone (I don&#8217;t know if anyone has even estimated it recently).</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/06/wrox-press-respond-to-the-art-of-deception-or-publishing-php6-books/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>It&#8217;s a bird, it&#8217;s a plane&#8230;no!&#8230;it&#8217;s some guy who vanished months ago!</title>
		<link>http://blog.astrumfutura.com/2009/06/its-a-bird-its-a-plane-no-its-some-guy-who-vanished-months-ago/</link>
		<comments>http://blog.astrumfutura.com/2009/06/its-a-bird-its-a-plane-no-its-some-guy-who-vanished-months-ago/#comments</comments>
		<pubDate>Fri, 19 Jun 2009 11:55:14 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[PHP General]]></category>
		<category><![CDATA[PHP Security]]></category>
		<category><![CDATA[irishisms]]></category>
		<category><![CDATA[php general]]></category>
		<category><![CDATA[php security]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=396</guid>
		<description><![CDATA[Long story short. I lost my job, had some medical issues, struck gold on a new contract, contract ended (with a nice bonus), need to find another contract in July, turned 30 (and got a tiny bit depressed that I can no longer validly refer to myself as &#8220;young&#8221;), lost more hair (I estimate the]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F06%2Fits-a-bird-its-a-plane-no-its-some-guy-who-vanished-months-ago%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F06%2Fits-a-bird-its-a-plane-no-its-some-guy-who-vanished-months-ago%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=irishisms,php+general,php+security,zend+framework&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Long story short. I lost my job, had some medical issues, struck gold on a new contract, contract ended (with a nice bonus), need to find another contract in July, turned 30 (and got a tiny bit depressed that I can no longer validly refer to myself as &#8220;young&#8221;), lost more hair (I estimate the total baldness effect to be a few years away), spent an hour convincing my dad that if his leg could hang at that angle I was calling the bloody ambulance no matter how many phobias he has about hospitals (he broke it in two places, got a massive plate put in, now complains about not being able to walk for a few months), played lots of Eve Online, discovered Empire: Total War ran for a maximum of 40mins before crashing (Asus MBs suck even if great to overclock), wrote three chapters in a semi-serious attempt to write a funny fantasy novel for fun, avoided being drunk for three months straight much to the horror of the locals (It&#8217;s a stereotype, but many Irish really do drink way too much), reinstalled Vista after the SP2 update fucked up, witnessed the return of a real Summer to Ireland for the first time in 3 years, realised that 3 years of little sun left me inexperienced with its effects and spent a week with both arms itching like crazy and covered in tiony blisters (stupid, stupid <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ), had my cat train me not to leave any windows open since he excels at unwanted infiltration, learned the redundancy toll at my previous employer was up to 15% of staff (happy I got out earlier), became reacquainted with the frequent headaches my sensitive eyes induce when exposed to the sun (I almost forgot it was up there for the past few years), &#8230;</p>
<p>Enough of that.</p>
<p>Being in a more stable point in this god awful recession, I&#8217;m edging back onto the PHP scene. My last post quickly became a total washout with my best intentions failing so miserably it was pathetic. What can I say? Recessions suck. Hospitals suck. Dads who break their legs every year especially suck (the leg breaking, not the person <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ).</p>
<p>To recapture some of my excitied and sorely disappointed readers, I&#8217;ll get those two ZF book chapters up shortly and get cracking on more. I&#8217;m actually on a few weeks of freedom so no excuses. If someone breaks a leg next week I may have a breakdown.</p>
<p>My profuse apologies for the misleading post in April &#8211; obviously since it&#8217;s now June it&#8217;s been a turbulant few months since it was posted.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/06/its-a-bird-its-a-plane-no-its-some-guy-who-vanished-months-ago/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Lack of updates&#8230;</title>
		<link>http://blog.astrumfutura.com/2009/04/lack-of-updates/</link>
		<comments>http://blog.astrumfutura.com/2009/04/lack-of-updates/#comments</comments>
		<pubDate>Wed, 08 Apr 2009 15:34:44 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=394</guid>
		<description><![CDATA[Filling in the blanks over my absence . Effective from today, I am a free agent. Free of the binds of employment that is. Well, until I find another position&#8230; Welcome to redundancy&#8230;meh. On the flip side, it was expected pretty much as it happened and I get a surprisingly generous redundancy payment out of]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F04%2Flack-of-updates%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F04%2Flack-of-updates%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=php&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Filling in the blanks over my absence <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Effective from today, I am a free agent. Free of the binds of employment that is. Well, until I find another position&#8230; Welcome to redundancy&#8230;meh. On the flip side, it was expected pretty much as it happened and I get a surprisingly generous redundancy payment out of it &#8211; which was not expected but much appreciated. As for expectations, I preempted the whole redundancy thing since I saw it coming given the activity in the market. So I&#8217;m in an entirely unsurprising predicament I have planned for.</p>
<p>As I suggested in the past couple of months, I am scouting for new work but the slow economy which was probably just blown apart by the new Irish Budget (increase taxes since nobody at Government level is able to reduce costs effectively&#8230;bunch of worthless gits) only emphasised by the amount of money I saved buying some items across the border at the weekend (Ireland raises VAT, UK&#8230;decreases VAT&#8230;and Sterling rates are really good right now &#8211; hillarious) is just that &#8211; slow. Apparently a CV is now taking several weeks to reach the interview shortlist so it&#8217;s become a mind numbing exercise in patience. I&#8217;m quite patience, but I can&#8217;t avoid getting a bit bored with sitting at home and I&#8217;m not looking forward to it that much.</p>
<p>Nevertheless, my hopes are high that a good job is around the corner and I have been in discussions with some contacts, and my weirdly niche skillset (programmer, financial specialist, etc. with lots of nice abbreviations after my name) simply requires that I show a bit of patience until a suitable opportunity appears &#8211; which is inevitable since my niche area is actually fairly solid even in the midst of a depression. The redundancy was over other areas of the sector underperforming, and other people needing to&#8230;well&#8230;borrow my work to keep themselves busy. I don&#8217;t begrudge them &#8211; and I won&#8217;t be there to see the mess they have already started to create plugging my specialist role <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>Playing the waiting game is something I&#8217;m good at &#8211; I have practically zero stress levels which is one part of my personality makeup I rather enjoy. Nervous at interviews? Piffle. Insecure in my abilities? Laughable. Hatez my job? I love my line of work &#8211; I&#8217;m good at it, I enjoy it, and I get paid extremely well for it.</p>
<p>But God, is job hunting slow this year! I&#8217;ve already heard of colleagues turning down jobs merely because the salary expectations have decreased so substantially. Some people just can&#8217;t take the hint to be more conservative in salary bases. Has nobody realised we are in a recession, and it&#8217;s time to accept a &#8220;hit&#8221; for a few years until the upswing (and our chances for career advancement) are improved? A stable job in a recession is not something to get all depressed and about because it pays 5k less than you expected &#8211; wake the fuck up! You&#8217;d swear the nation never had a recession before! I remember the 80s and 90s &#8211; especially the 80s since my Dad was seriously struggling in those days and it left an impression in my childhood memories.</p>
<p>In any case, this is why I&#8217;ve been largely offline the past few weeks &#8211; too busy wrapping up outstanding private projects, getting my CV nailed down, holding the usual pep talk meetings where recruiters swear blind to be your best friend (they are suffering too from the slow job market), working my contacts, and tracking down rumours of possible top-secret jobs not being openly advertised. I estimate at least a month until I am secured in a new office with a team of overly eager underlings (er&#8230;highly skilled professionals) to bend to my will (ahem&#8230;motivate, train and supervise). I could grab something short term, but I&#8217;d prefer to dig around for something and take a breather for a few weeks.</p>
<p>The downside is, obviously, weeks of freedom. I&#8217;m going to get pretty bored very fast, but should make more headway on the ZF book after this minor side adventure. Usually I&#8217;d scout around and grab a short term contract with a side dish of consulting, but I feel like enjoying my unemployed state for a few weeks to recharge and work up some enthusiasm for my next position. That I can afford to do so is frightening, but I have been lucky in that I escaped the equity market long before it seriously collapsed putting me in the weird position of waiting for the markets to recover so I can enter the market again and make a modest sum. I&#8217;m usually not egotistical (lies! lies!), but I saw it coming when the housing markets here in Ireland started to falter. Anyone curious can look at a graph of the ISEQ Index and fall down laughing at how it performed.</p>
<p>I think I fell off topic somewhere? Oh well, been a while since I blogged so endure the long post <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . If you feel like offering moral support, send a large ISK donation to &#8220;Maugrim McFiriba&#8221; in Eve Online &#8211; I&#8217;ll need more ships to pass the time in Eve I think <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . I&#8217;ve been enjoying the game for a while now, and it&#8217;s a nice diversion when the writing peters off and I&#8217;m not in the mood for relaxing with a good book.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/04/lack-of-updates/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Cowen Is My Shepherd&#8230;</title>
		<link>http://blog.astrumfutura.com/2009/03/cowen-is-my-shepherd/</link>
		<comments>http://blog.astrumfutura.com/2009/03/cowen-is-my-shepherd/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 14:38:43 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=388</guid>
		<description><![CDATA[Disclaimer: This entry offers a personal political opinion on the current state of the economy of Ireland under the incompetent leadership of Brian Cowen and Brian Lenihan. Sourced from a post on politics.ie. COWEN IS MY SHEPHERD, I SHALL NOT WORK. HE LEADETH ME BESIDE STILL FACTORIES. HE RESTORETH MY FAITH IN THE FINE GAEL.]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F03%2Fcowen-is-my-shepherd%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F03%2Fcowen-is-my-shepherd%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=php&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><strong>Disclaimer:</strong> This entry offers a personal political opinion on the current state of the economy of Ireland under the incompetent leadership of Brian Cowen and Brian Lenihan. Sourced from a post on politics.ie.</p>
<blockquote><p>COWEN IS MY SHEPHERD, I SHALL NOT WORK.</p>
<p>HE LEADETH ME BESIDE STILL FACTORIES.</p>
<p>HE RESTORETH MY FAITH IN THE FINE GAEL.</p>
<p>HE GUIDETH ME TO THE PATH OF UNEMPLOYMENT.</p>
<p>YEA, THOUGH I WAIT FOR MY DOLE,</p>
<p>I OWN THE BANK THAT REFUSES ME.</p>
<p>COWEN HAS ANOINTED MY INCOME WITH TAXES,</p>
<p>MY EXPENSES RUNNETH OVER MY INCOME,</p>
<p>SURELY, POVERTY AND HARD LIVING WILL FOLLOW ME ALL THE  DAYS OF HIS<br />
TERM.</p>
<p>FROM HENCE FORTH WE WILL LIVE ALL THE DAYS  OF OUR LIVES IN A RENTED<br />
HOME WITH AN OVERSEAS LANDLORD.</p>
<p>I AM GLAD I AM IRISH,</p>
<p>I AM GLAD THAT I AM FREE.</p>
<p>BUT I WISH I WAS A DOG</p>
<p>AND COWEN WAS A TREE.
</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/03/cowen-is-my-shepherd/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Unit Testing: One Test, One Assertion &#8211; Why It Works</title>
		<link>http://blog.astrumfutura.com/2009/02/unit-testing-one-test-one-assertion-why-it-works/</link>
		<comments>http://blog.astrumfutura.com/2009/02/unit-testing-one-test-one-assertion-why-it-works/#comments</comments>
		<pubDate>Mon, 16 Feb 2009 17:37:00 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[PHP General]]></category>
		<category><![CDATA[PHP Security]]></category>
		<category><![CDATA[irishisms]]></category>
		<category><![CDATA[php general]]></category>
		<category><![CDATA[php security]]></category>
		<category><![CDATA[rantings]]></category>
		<category><![CDATA[snarl]]></category>
		<category><![CDATA[tdd]]></category>
		<category><![CDATA[unit testing]]></category>
		<category><![CDATA[xp programming]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=385</guid>
		<description><![CDATA[In my last post I touched on the topic of multiple assertions in a unit test and linked it somewhat harshly to being a factor in &#8220;lazy&#8221; or shallow testing. I actually didn&#8217;t intend on linking them at all, but the truth is that unit testing isn&#8217;t a series of mutually exclusive practices &#8211; they]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F02%2Funit-testing-one-test-one-assertion-why-it-works%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F02%2Funit-testing-one-test-one-assertion-why-it-works%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=irishisms,php+general,php+security,rantings,snarl,tdd,unit+testing,xp+programming&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>In my last post I touched on the topic of multiple assertions in a unit test and linked it somewhat harshly to being a factor in &#8220;lazy&#8221; or shallow testing. I actually didn&#8217;t intend on linking them at all, but the truth is that unit testing isn&#8217;t a series of mutually exclusive practices &#8211; they are all linked to varying degrees. I&#8217;m sure I have at least a degree of laziness myself in testing <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<h3>The Basic Idea</h3>
<p>As a recap, the idea is that every unit test should only have one single assertion. It&#8217;s a fairly well known method to combat a range of problems evident in assertion loaded tests where the numerous assertions obscure the meaning of the test, and where a failed test does not tell you the specific assertions which failed (since tests traditionally fail after any assertion failure, the remaining assertions are never executed thus leaving you blind to whether they would have passed or failed). There are other problems with the approach as well &#8211; which is why I do not like seeing multiple assertions in a single test. I&#8217;m not the only one &#8211; I think. And just as there are problems, there are also exceptions when multiple assertions might prove necessary &#8211; personally I think this scenario is pretty rare however. After my years of unit testing, I certainly have not encountered all that many.</p>
<p>These effects by themselves make me fairly comfortable in enforcing Single Assertions in tests as a rule, not a guideline. Guidelines are broken easily, but with rules you can at least strike back and make certain you don&#8217;t run aground on someone else&#8217;s inexperience or ill fated experiments in making testing &#8220;easier&#8221;. It&#8217;s also extremely easy to detect <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . PHPUnit, for example, reports the number of both tests and assertions executed &#8211; so you can calculate a quick ratio of assertions to tests in mere seconds. I&#8217;m going to start calling it the Obscurity Ratio! Obviously, a ratio of 1:1 would be perfect &#8211; but I&#8217;m sure we can accept some multiple assertions within a tolerance level. A ratio of more than 1.1:1 would indicate creeping obscurity (a signal it&#8217;s time for me to intervene, refactor, and do some mutation testing for extra assurance). A ratio of 2:1 indicates a lost cause. Anything higher and God help you all.</p>
<h3>This Sounds Like A Bad Idea!</h3>
<p>In watching the reactions to my original post (and not just the comments here), I&#8217;ve noticed that the excuses are generally similar. People have leaned towards justifying using multiple assertions for complex return values, or pointed out that my example was too simple (since that really really shows its a Bad Idea&trade; <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ), or that all the mini-tests would take too long to write, and even longer to execute, or that the world will end since Peter Petrelli thinks this is all a Bad Idea&trade; and everyone knows Sylar invented it anyway.</p>
<p>Not to completely oppose all the opinions (it really was a simple example), but people are spending too much time looking at the end result, and not enough at the process behind it all. And it&#8217;s by missing the process that you are missing the point.</p>
<p>Now let me disclaim a little &#8211; I&#8217;m really really sure there are times multiple assertions are needed. So my main point is not that this is an absolute rule with no possible exceptions so help me God, rather that it should be a rule unless you are literally forced to tackle an exception to it.</p>
<h3>Why It&#8217;s A Good Idea&#8230;</h3>
<p>Unit Testing has various interpretations. It&#8217;s original genesis promoted the verification of source code, a means of making sure code worked. It was not long before the obvious flaws in that thinking emerged &#8211; how do you verify the verified? You already know the code works before you write the test, so what value does it really bring to the table? Does it really promote code quality and rapid development &#8211; or just create a horrible task some low ranking developer will be landed with?</p>
<p>This sparked a revolution &#8211; Test Driven Design (TDD). In TDD, tests stepped back from verifying, and entered a role as specifications. Before you wrote the source code, you first wrote a test which specified the behaviour you intended on adding. Once you had the behaviour specified, you then wrote just enough source code to make that test pass. The result was a process of simple steps &#8211; and here&#8217;s where I diverge from others. A simple example works &#8211; because all half decent source code is nothing more than an amalgamation of simple examples &#8211; in fact, I dare anyone to prove otherwise. Then I can show you the PHP manual and you can explain how the hell you made PHP that complex <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
<p>In TDD we back away from testing complex highly involved code after the fact (too late then!), to preemptively writing tests to produce simpler straightforward code produced in steps. Simpler is better &#8211; always. The differences can be startling. Try writing two identical libraries both ways and you&#8217;ll see how.</p>
<p>It&#8217;s this notion of complexity that is often used to justify multiple assertions &#8211; if you break it down into the simple components that that complexity was built out of, multiple assertions don&#8217;t have a leg to stand on (just the rare instances out of your control because they absolutely must be done). The most common (just to preempt you all) scenarios for complexity in testing assertions boil down to BIG stuff &#8211; deeply nested stuff. Arrays and XML are the most common ones. Mathematical equations for relativity are simpler than those!</p>
<p>But let&#8217;s pass on through to the other benefits instead of obsessing over just one.</p>
<p>If your tests double as your specification to describe how a class should behave (and yes, I&#8217;m robbing the definition list in Behaviour-Driven Development, or BDD, blind) or documentation &#8211; you&#8217;re doing nothing wrong. Tests should document behaviour. This is why test method names are important &#8211; they summarise the behaviour the test is verifying.</p>
<p>Now add another little rule: every test only verifies one single behaviour. When we make that connection we realise something even more startling&#8230;</p>
<h3>1 Behaviour == 1 Assertion</h3>
<p>Now we&#8217;re into the meat of my madness, the gritty reality of the one assertion per test rule. Any behaviour is, by its very nature, both specific and unique. It does not require multiple assertions. Either it does one single thing, or it doesn&#8217;t do it at all. It&#8217;s black and white. The only danger is that you get so smart, you think in terms of big behaviours which are really just lots of little behaviours bundled together. Enjoy applying TDD in that case&#8230;it will sink you faster than you can say &#8220;Peter Petrelli Is Depressing&#8221; and you&#8217;ll end up back in the land of writing tests AFTER the code. Anyone going to admit to doing that? <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  We all know who we are (yes, I do it too now and again).</p>
<p>That&#8217;s why Test-Driven Design is so effective. It enforces a habit (once you actually understand the damn practice which is almost designed to hide the behaviour facet!) of specifying class behaviour by behaviour, assertion by assertion. It breaks down the complex overall purpose of any class into discrete simple steps, a series of tiny goals you can easily achieve.</p>
<p>Simple, tiny, discrete &#8211; like individual assertions. It&#8217;s THAT simple.</p>
<p>That&#8217;s why the one assertion per test is a good idea &#8211; because it&#8217;s obvious in TDD. It&#8217;s what works, and it ensures your tests do exactly what they&#8217;re suppossed to be doing &#8211; verifying discrete behaviour, and documenting that behaviour to make other developer&#8217;s lives a bit easier (and saner).</p>
<h3>The Spontaneous Test Population Explosion Myth</h3>
<p>This is the one myth everyone knows targets the one assertion per test rule. The question is whether it&#8217;s a myth, or whether something else is. The idea is that by requiring one assertion per test, you end up with more tests, more code, higher execution times, etc. Which is to say&#8230;more behaviours. Which is to say &#8211; where the hell did the new behaviours come from?</p>
<p>Unwittingly, the excuse reveals itself to be the myth. If you have tests, and they can survive as multiple tests &#8211; you pretty much admitted your original tests were collections of behaviours. Welcome to the land of Obscure Tests &#8211; they test many things, and nobody can figure out just what.</p>
<p>Tests are documentation. Like any form of writing, you can block together ideas into a monologue or use properly formatted paragraphs and bullet points to break things down into a more digestable form for reading. It comes with a cost, but discrete tests are more helpful as documentation.</p>
<p>As for execution times, I really don&#8217;t understand why people find this a problem. PHPUnit let&#8217;s you run any test class in isolation, and you can group test suites in any shape or form. If your tests are running slow, treat them like any other code &#8211; use XDebug to locate the bottlenecks and slow tests and do something about them. Use more efficient code, refactor them to hell and back, isolate the slow tests &#8211; we can all do performance optimisation.</p>
<p>The other alternative is to let tests run in the background and use a notification system to report failures while you go away and write another test or two. I do this myself &#8211; see what notification apps you can hook into from PHP or some other test enviroment tool. I had working Snarl code for a PHP extension working under Windows somewhere if you can use a compiler and really need it.</p>
<h3>Attitude Counts</h3>
<p>Another compelling reason to adopt one assertion per test is your ego. Look at me &#8211; I have an ego, I write stuff because I enjoy doing it and am motivated by other people reading it and thinking it&#8217;s the best thing ever written <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . We all have egos. My ego has me writing free books (though the prospect of a new Macbook Pro is another motive&#8230;hehehe).</p>
<p>Unfortunately our ego is also a major enemy in unit testing. If you find yourself saying you prefer multiple assertions because it works for you, and you can understand them, and they make perfect sense to you, and hey, your code works with 200% code coverage &#8211; then count how many &#8220;you&#8221; words you just used (or &#8220;I&#8221; if writing first person!).</p>
<p>It&#8217;s not about you!</p>
<p>Other developers have to read your tests eventually, unless it&#8217;s a top secret project only you will ever work on. Don&#8217;t saddle the rest of the world with the product of your ego. Everyone finds simpler tests easier to work with. The general rule of thumb is pretty simple &#8211; if you give someone a copy of your tests, and nothing else, could they ever write the code to fit those tests in a reasonable time from scratch without begging you for assistance?</p>
<h3>Conclusion</h3>
<p>More food for thought <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . No pretty code to look at for this one so if you haven&#8217;t read the last post yet, go read it now.</p>
<p>Until next time&#8230;when I find something else to moan about.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/02/unit-testing-one-test-one-assertion-why-it-works/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Zend Framework Page Caching: Part 3b: Tagging For Static File Caches</title>
		<link>http://blog.astrumfutura.com/2009/01/zend-framework-page-caching-part-3b-tagging-for-static-file-caches/</link>
		<comments>http://blog.astrumfutura.com/2009/01/zend-framework-page-caching-part-3b-tagging-for-static-file-caches/#comments</comments>
		<pubDate>Mon, 19 Jan 2009 17:33:30 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[irishisms]]></category>
		<category><![CDATA[surviving the deep end]]></category>
		<category><![CDATA[tutorial]]></category>
		<category><![CDATA[zend framework]]></category>
		<category><![CDATA[zf proposal]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=382</guid>
		<description><![CDATA[Continued from Part 3&#8230; Let&#8217;s make two more changes to complete the process. Here&#8217;s the new Controller from earlier where we set the tag &#8220;entries&#8221; on any Actions where blog entries are displayed or listed. [geshi lang=php]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fzend-framework-page-caching-part-3b-tagging-for-static-file-caches%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fzend-framework-page-caching-part-3b-tagging-for-static-file-caches%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=irishisms,surviving+the+deep+end,tutorial,zend+framework,zf+proposal&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><em>Continued from <a href="http://blog.astrumfutura.com/archives/383-Zend-Framework-Page-Caching-Part-3-Tagging-For-Static-File-Caches.html">Part 3&#8230;</a></em></p>
<p>Let&#8217;s make two more changes to complete the process. Here&#8217;s the new Controller from earlier where we set the tag &#8220;entries&#8221; on any Actions where blog entries are displayed or listed.</p>
<p>[geshi lang=php]<?php</p>
<p>class EntryController extends Zend_Controller_Action<br />
{</p>
<p>    public function init()<br />
    {<br />
        $this->_helper->cache(array(&#8216;index&#8217;), array(&#8216;tag1&#8242;,&#8217;entries&#8217;,'tag3&#8242;));<br />
        $this->_helper->cache->useCleaner(&#8216;entry&#8217;, array(&#8216;process&#8217;,'delete&#8217;));<br />
    }</p>
<p>    public function indexAction()<br />
    {<br />
        // show some entries, page should be cached<br />
    }</p>
<p>    public function processAction()<br />
    {</p>
<p>        // store the blog entry by whatever means necessary<br />
    }</p>
<p>    public function deleteAction()<br />
    {<br />
        // delete one or more entries<br />
    }</p>
<p>}[/geshi]</p>
<p>Based on the tags being used, we can now simplify our previously nightmarish Cleaner to a single line!</p>
<p>[geshi lang=php]<?php</p>
<p>class ZFExt_Cache_Cleaner_Abstract<br />
{</p>
<p>    protected $_cache = null;</p>
<p>    public function __construct()<br />
    {<br />
        // Needing the Action Helper here may suggest the need to extract the<br />
        // functionality common to Helpers and Cleaners into it's own<br />
        // class for sharing<br />
        // Being an article, let's skip the obvious refactoring need before this<br />
        // becomes another book...<br />
        if (Zend_Controller_Action_HelperBroker::hasHelper('cache')) {<br />
            $this->_cache = Zend_Controller_Action_HelperBroker::getExistingHelper(&#8216;cache&#8217;);<br />
        }<br />
        $this->_cache = Zend_Controller_Action_HelperBroker::getStaticHelper(&#8216;cache&#8217;);<br />
    }</p>
<p>}</p>
<p>class EntryCleaner extends ZFExt_Cache_Cleaner_Abstract<br />
{</p>
<p>    public function afterProcess()<br />
    {<br />
        $this->_cache->removeTaggedPageCache(array(&#8216;entries&#8217;));<br />
    }</p>
<p>    public function afterDelete()<br />
    {<br />
        $this->_cache->removeTaggedPageCache(array(&#8216;entries&#8217;));<br />
    }</p>
<p>}[/geshi]</p>
<p>I think we&#8217;ll stop here for now!</p>
<h3>Conclusion</h3>
<p>Over the last three (well, four if you count I ran out of space on Part 2 and needed a 2b <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> ) parts of this weekend series I&#8217;ve covered page caching with a focus on caching output to static HTML files to offload work from Apache and PHP.</p>
<p>This caching strategy allows the webserver to avoid PHP completely, or alternatively for a frontend nginx/lighty reverse proxy to avoid Apache completely. Either way, it results in a very fast and efficient caching mechanism for entire pages which can be linked to Tags and Cleaners so they are updated only when the data they were originally generated from has changed.</p>
<p>It should be noted that while static HTML caching is one of the fastest possible caching mechanisms, it is not the most flexible. It is best suited to standalone, or small 2-3 unit scaled solutions, where filesystem operations can be unified with a frontend HTTP server. Trying to sync this style of caching across servers is to be avoided. It is also not suitable for highly dynamic pages which continually update or are specific to each visitor. In these cases the more expensive caching methods are often needed, though if the dynamic portions are small enough it might be worth delegating the generation of those dynamic portions to AJAX requests from the statically cached page, so that at least the bulk of any page is cached.</p>
<p>Additionally, once you do reach the point where static caching cannot be used, you should of course examine other caching options across the parts of the application impacted. Remember that you can cache database results, individual template output (even partials), CPU or memory intensive operations, etc.</p>
<p>In closing, I hope this series has offered a few good ideas <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/01/zend-framework-page-caching-part-3b-tagging-for-static-file-caches/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Zend Framework Page Caching: Part 2b: Controller Based Cache Management</title>
		<link>http://blog.astrumfutura.com/2009/01/zend-framework-page-caching-part-2b-controller-based-cache-management/</link>
		<comments>http://blog.astrumfutura.com/2009/01/zend-framework-page-caching-part-2b-controller-based-cache-management/#comments</comments>
		<pubDate>Sun, 18 Jan 2009 17:45:00 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=380</guid>
		<description><![CDATA[Continuing from Part 2! Check out the direct() and preDispatch() methods &#8211; using these we can setup what to cache, start caching, and all without needing regular expressions since our Static backend is driven by the current REQUEST URI. Given all the above changes, it&#8217;s no surprise the Static Backend has had a few updates!]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fzend-framework-page-caching-part-2b-controller-based-cache-management%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fzend-framework-page-caching-part-2b-controller-based-cache-management%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=php&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p><em>Continuing from Part 2!</em></p>
<p>Check out the direct() and preDispatch() methods &#8211; using these we can setup what to cache, start caching, and all without needing regular expressions since our Static backend is driven by the current REQUEST URI.</p>
<p>Given all the above changes, it&#8217;s no surprise the Static Backend has had a few updates!</p>
<p>[geshi lang=php]<?php</p>
<p>class ZFExt_Cache_Backend_Static extends Zend_Cache_Backend implements Zend_Cache_Backend_Interface<br />
{</p>
<p>    const DEBUG_HEADER = 'DEBUG HEADER : This is a cached page !';</p>
<p>    // Available options<br />
    protected $_options = array(<br />
        'public_dir' => null,<br />
        &#8216;file_extension&#8217; => &#8216;.html&#8217;,<br />
        &#8216;index_filename&#8217; => &#8216;index&#8217;,<br />
        &#8216;file_locking&#8217; => true,<br />
        &#8216;cache_file_umask&#8217; => 0600,<br />
        &#8216;debug_header&#8217; => false<br />
    );</p>
<p>    // Test if a cache is available for the given id and (if yes) return it<br />
    // (false else)<br />
    // $id should be the REQUEST_URI whose static file is to be deleted<br />
    public function load($id, $doNotTestCacheValidity = false)<br />
    {<br />
        $id = $this->_decodeId($id);<br />
        if (empty($id) || $id == &#8216;_&#8217;) {<br />
            $id = $this->_detectId();<br />
        }<br />
        if (!$this->_verifyPath($id)) {<br />
            Zend_Cache::throwException(&#8216;Invalid cache id: does not match expected public_dir path&#8217;);<br />
        }<br />
        if ($doNotTestCacheValidity) {<br />
            $this->_log(&#8220;ZFExt_Cache_Backend_Static::load() : \$doNotTestCacheValidity=true is unsupported by the Static backend&#8221;);<br />
        }<br />
        $fileName = basename($id);<br />
        if (empty($fileName)) {<br />
            $fileName = $this->_options['index_filename'];<br />
        }<br />
        $pathName = $this->_options['public_dir'] . dirname($id);<br />
        $file = $pathName . &#8216;/&#8217; . $fileName . $this->_options['file_extension'];<br />
        if (file_exists($file)) {<br />
            $content = file_get_contents($file);<br />
            // move debug header to Frontend to prevent these gymnastics<br />
            return str_replace(self::DEBUG_HEADER, &#8221;, $content);<br />
        }<br />
        return false;<br />
    }</p>
<p>    // Test if a cache is available or not<br />
    // $id should be the REQUEST_URI whose static file is to be deleted<br />
    public function test($id)<br />
    {<br />
        $id = $this->_decodeId($id);<br />
        if (!$this->_verifyPath($id)) {<br />
            Zend_Cache::throwException(&#8216;Invalid cache id: does not match expected public_dir path&#8217;);<br />
        }<br />
        $fileName = basename($id);<br />
        if (empty($fileName)) {<br />
            $fileName = $this->_options['index_filename'];<br />
        }<br />
        $pathName = $this->_options['public_dir'] . dirname($id);<br />
        $file = $pathName . &#8216;/&#8217; . $fileName . $this->_options['file_extension'];<br />
        if (file_exists($file)) {<br />
            return true;<br />
        }<br />
        return false;<br />
    }</p>
<p>    // Save content to a static content file in /public directory<br />
    // Note: We&#8217;re ignoring the ID as its not required.<br />
    public function save($data, $id, $tags = array(), $specificLifetime = false)<br />
    {<br />
        clearstatcache();<br />
        $requestUri = $this->_detectId();<br />
        $fileName = basename($requestUri);<br />
        if (empty($fileName)) {<br />
            $fileName = $this->_options['index_filename'];<br />
        }<br />
        $pathName = $this->_options['public_dir'] . dirname($requestUri);<br />
        if (!file_exists($pathName)) {<br />
            mkdir($pathName, $this->_options['cache_file_umask'], true);<br />
        }<br />
        if ($id !== &#8216;_&#8217;) { // empty ID since a Capture<br />
            $dataUnserialized = unserialize($data);<br />
        } else {<br />
            $dataUnserialized = array();<br />
            $dataUnserialized['data'] = $data;<br />
        }<br />
        if ($this->_options['debug_header']) {<br />
            $dataUnserialized['data'] =<br />
                self::DEBUG_HEADER . $dataUnserialized['data'];<br />
        }<br />
        $file = $pathName . &#8216;/&#8217; . $fileName . $this->_options['file_extension'];<br />
        if ($this->_options['file_locking']) {<br />
            $result = file_put_contents($file, $dataUnserialized['data'], LOCK_EX);<br />
        } else {<br />
            $result = file_put_contents($file, $dataUnserialized['data']);<br />
        }<br />
        @chmod($file, $this->_options['cache_file_umask']);<br />
        if (count($tags) > 0) {<br />
            $this->_log(self::TAGS_UNSUPPORTED_BY_SAVE_OF_STATIC_BACKEND);<br />
        }<br />
        return (bool) $result;<br />
    }</p>
<p>    // Remove a cache record<br />
    // $id should be the REQUEST_URI whose static file is to be deleted<br />
    public function remove($id)<br />
    {<br />
        $id = $this->_decodeId($id);<br />
        if (!$this->_verifyPath($id)) {<br />
            Zend_Cache::throwException(&#8216;Invalid cache id: does not match expected public_dir path&#8217;);<br />
        }<br />
        $fileName = basename($id);<br />
        if (empty($fileName)) {<br />
            $fileName = $this->_options['index_filename'];<br />
        }<br />
        $pathName = $this->_options['public_dir'] . dirname($id);<br />
        $file = $pathName . &#8216;/&#8217; . $fileName . $this->_options['file_extension'];<br />
        if (!file_exists($file)) {<br />
            return true;<br />
        }<br />
        return unlink($file);<br />
    }</p>
<p>    // Remove a cache record recursively (i.e. the file AND matching directory)<br />
    // it ain&#8217;t perfect &#8211; there may be no file matching the directory name<br />
    // (but you get the point I&#8217;m sure!)<br />
    // $id should be the REQUEST_URI whose static file &#038; dir tree is to be deleted<br />
    public function removeRecursively($id)<br />
    {<br />
        $id = $this->_decodeId($id);<br />
        if (!$this->_verifyPath($id)) {<br />
            Zend_Cache::throwException(&#8216;Invalid cache id: does not match expected public_dir path&#8217;);<br />
        }<br />
        $fileName = basename($id);<br />
        if (empty($fileName)) {<br />
            $fileName = $this->_options['index_filename'];<br />
        }<br />
        $pathName = $this->_options['public_dir'] . dirname($id);<br />
        $file = $pathName . &#8216;/&#8217; . $fileName . $this->_options['file_extension'];<br />
        $directory = $pathName . &#8216;/&#8217; . $fileName;<br />
        if (file_exists($directory)) {<br />
            if (!is_writable($directory)) {<br />
                return false;<br />
            }<br />
            foreach (new DirectoryIterator($directory) as $file) {<br />
                if (true === $file->isFile()) {<br />
                    if (false === unlink($file->getPathName())) {<br />
                        return false;<br />
                    }<br />
                }<br />
            }<br />
            rmdir(dirname($path));<br />
        }<br />
        if (file_exists($file)) {<br />
            if (!is_writable($file)) {<br />
                return false;<br />
            }<br />
            return unlink($file);<br />
        }<br />
    }</p>
<p>    // Clean some cache records<br />
    // Not implemented here since we would need a backend tagging system given<br />
    // that static files themselves cannot be tagged in the filename.<br />
    public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array())<br />
    {<br />
        switch ($mode) {<br />
            case Zend_Cache::CLEANING_MODE_ALL:<br />
            case Zend_Cache::CLEANING_MODE_OLD:<br />
            case Zend_Cache::CLEANING_MODE_MATCHING_TAG:<br />
            case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG:<br />
            case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG:<br />
                $this->_log(&#8220;ZFExt_Cache_Backend_Static : Cleaning Modes Currently Unsupported By This Backend&#8221;);<br />
                break;<br />
            default:<br />
                Zend_Cache::throwException(&#8216;Invalid mode for clean() method&#8217;);<br />
                break;<br />
        }<br />
    }</p>
<p>    // Encoded by ZFExt_Cache_Backend_Static_Adapter<br />
    protected function _decodeId($id)<br />
    {<br />
        // another workaround since Zend_Cache_Core prevents<br />
        // empty or null IDs which we&#8217;ll have when Capturing<br />
        // and before the REQUEST_URI is checked<br />
        if ($id == &#8216;_&#8217;) {<br />
            return &#8221;;<br />
        }<br />
        return pack(&#8216;H*&#8217;, $id);<br />
    }</p>
<p>    // &#8220;Danger, Will Robinson!&#8221;<br />
    // Sanity check to ascertain whether path is within the configured<br />
    // public_dir path<br />
    protected function _verifyPath($path)<br />
    {<br />
        $path = realpath($path);<br />
        $base = realpath($this->_options['public_dir']);<br />
        return strncmp($path, $base, strlen($base)) !== 0;<br />
    }</p>
<p>    protected function _detectId()<br />
    {<br />
        // should strip query strings in future<br />
        // along with other fragments<br />
        return $_SERVER['REQUEST_URI'];<br />
    }</p>
<p>}[/geshi]</p>
<p>Two more source code listings remain &#8211; here&#8217;s the revised Bootstrap fragment:</p>
<p>[geshi lang=php]class ZFExt_Bootstrap<br />
{</p>
<p>    // &#8230;</p>
<p>    public function run()<br />
    {<br />
        $this->setupEnvironment();<br />
        // Implement Page Caching at Bootstrap level before any<br />
        // MVC operations so these operations can be completely<br />
        // avoided when a valid cache exists<br />
        $this->usePageCache();<br />
        // If a valid cache exists, execution exits!<br />
        $this->prepare();<br />
        $response = self::$frontController->dispatch();<br />
        $this->sendResponse($response);<br />
    }</p>
<p>    public function usePageCache()<br />
    {<br />
        $frontend = new ZFExt_Cache_Frontend_Capture();<br />
        $backendOptions = array(<br />
            &#8216;debug_header&#8217; => true,<br />
            &#8216;public_dir&#8217; => self::$root . &#8216;/public&#8217;<br />
        );<br />
        $backend = new ZFExt_Cache_Backend_Static($backendOptions);<br />
        // use our Adapter to deal with the Core&#8217;s private validation<br />
        $cache = new ZFExt_Cache_Backend_Static_Adapter(<br />
            Zend_Cache::factory($frontend, $backend)<br />
        );<br />
        // Add the new cache to the Cache Control Action Helper<br />
        Zend_Controller_Action_HelperBroker::addPrefix(&#8216;ZFExt_Controller_Action_Helper&#8217;);<br />
        Zend_Controller_Action_HelperBroker::getStaticHelper(&#8216;Cache&#8217;)->addCache(&#8216;page&#8217;, $cache);<br />
        // Assume all caching initiated by Controllers (need to detect OB otherwise)<br />
    }<br />
}[/geshi]</p>
<p>After all of that&#8230;our Controller has morphed into the following:</p>
<p>[geshi lang=php]<?php</p>
<p>class EntryController extends Zend_Controller_Action<br />
{</p>
<p>    public function init()<br />
    {<br />
        $this->_helper->cache(array(&#8216;index&#8217;));<br />
        $this->_helper->cache->useCleaner(&#8216;entry&#8217;, array(&#8216;process&#8217;,'delete&#8217;));<br />
    }</p>
<p>    public function indexAction()<br />
    {<br />
        // show some entries, page should be cached<br />
    }</p>
<p>    public function processAction()<br />
    {<br />
        // store the blog entry by whatever means necessary<br />
    }</p>
<p>    public function deleteAction()<br />
    {<br />
        // delete one or more entries<br />
    }</p>
<p>}[/geshi]</p>
<h3>Conclusion</h3>
<p>Part 3 will start to address some of the weakness in the system so far (like track who has cached what and where <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ), but for now the system, in its prototype format, is operational. We can now statically cache HTML output on the fly from our controllers and implement Cleaners to clear that cache as actions dictate. We&#8217;ve even established the beginnings of a cache management system which favours Controller based instructions over regular expression url definitions. It&#8217;s still not fluid enough to be configurable, but we&#8217;re very close to that level.</p>
<p>Part 3 tomorrow!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/01/zend-framework-page-caching-part-2b-controller-based-cache-management/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Seven Things: Chained To Infinity!</title>
		<link>http://blog.astrumfutura.com/2009/01/seven-things-chained-to-infinity/</link>
		<comments>http://blog.astrumfutura.com/2009/01/seven-things-chained-to-infinity/#comments</comments>
		<pubDate>Sat, 03 Jan 2009 01:06:00 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[PHP General]]></category>
		<category><![CDATA[PHP Security]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=374</guid>
		<description><![CDATA[Thanks to Rob Allen, I&#8217;ve been tagged in this chained blog posting phenomenon so here&#8217;s my 7&#215;7 to preserve my good fortunes for this coming year and stave off bankruptcy or whatever could happen if I don&#8217;t . Seven random/weird things about me: - I don&#8217;t have a formal Computer Science degree, in fact I]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fseven-things-chained-to-infinity%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fseven-things-chained-to-infinity%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=php&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Thanks to <a href="http://akrabat.com/" >Rob Allen</a>, I&#8217;ve been tagged in this chained blog posting phenomenon so here&#8217;s my 7&#215;7 to preserve my good fortunes for this coming year and stave off bankruptcy or whatever could happen if I don&#8217;t <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p>Seven random/weird things about me:</p>
<p>- I don&#8217;t have a formal Computer Science degree, in fact I studied Commerce originally (Honors!) and Computer Science as a sideline.<br />
- My first programming experience was copying BASIC code from adventure books typed into a Commodore 64k a few centuries ago. I still have the Commodore &#8211; and it&#8217;s still operational!<br />
- My first frequent activity on a real PC was playing Duke Nukem 3D.<br />
- My most recent physical defect is a scarcity of hair which started during 2008. I blame Dad. I hear he blames his Dad. Pretty sure that goes back a ways <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .<br />
- I write sci-fi/fantasy short stories in some of my free time.<br />
- Contrary to the Irish stereotype, I am not frequently intoxicated as some have suggested. That&#8217;s just a vile rumour with absolutely no concrete evidence anyone who wishes to continue living can produce.<br />
- I first learned PHP to contribute to a game called Solar Empire in 1998.</p>
<p>To avenge my own tagging, I&#8217;m taking out my ire on the following victims:</p>
<p>- <a href="http://www.travisswicegood.com/">Travis Swicegood</a> since he wrote the first published GIT book and made me pay cash to read it<br />
- <a href="http://www.norm2782.com/">Jurrien Stutterheim</a> for volunteering to assist developing Zend_Feed_Reader (no good deed goes unpunished!)<br />
- <a href="http://tobiasgies.blogspot.com/">Tobias Gies</a> for smugly pointing out spelling errors on my new online book!<br />
- <a href="http://karwin.blogspot.com/">Bill Karwin</a> whose contributions to Phing power the Docbook automation of the book<br />
- <a href="http://www.thomasweidner.com">Thomas Weidner</a> who lets me safely use Gaelic characters in my ZF applications and insulate us all from the Anglic hordes.<br />
- <a href="http://codeutopia.net/blog/">Jani Hartikainen</a> since he said nice things on Twitter, and that surely can&#8217;t pass without punishment!<br />
- <a href="http://djcapelis.livejournal.com">D.J. Capelis</a> who I just reconnected with over Twitter &#8211; been years since we were active members of the old Solar Empire browser game developer community.</p>
<p>The rules according to Mr. Allen:</p>
<p>* Link your original tagger(s), and list these rules on your blog.<br />
* Share seven facts about yourself in the post &#8211; some random, some wierd.<br />
* Tag seven people at the end of your post by leaving their names and the links to their blogs.<br />
* Let them know they&#8217;ve been tagged by leaving a comment on their blogs and/or Twitter.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/01/seven-things-chained-to-infinity/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Book Launched! Zend Framework: Surviving The Deep End</title>
		<link>http://blog.astrumfutura.com/2009/01/book-launched-zend-framework-surviving-the-deep-end/</link>
		<comments>http://blog.astrumfutura.com/2009/01/book-launched-zend-framework-surviving-the-deep-end/#comments</comments>
		<pubDate>Thu, 01 Jan 2009 17:34:12 +0000</pubDate>
		<dc:creator>Pádraic Brady</dc:creator>
				<category><![CDATA[Irishisms]]></category>
		<category><![CDATA[PHP General]]></category>
		<category><![CDATA[PHP Security]]></category>
		<category><![CDATA[Zend Framework]]></category>
		<category><![CDATA[book]]></category>
		<category><![CDATA[irishisms]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[php general]]></category>
		<category><![CDATA[php security]]></category>
		<category><![CDATA[surviving the deep end]]></category>
		<category><![CDATA[zend framework]]></category>

		<guid isPermaLink="false">http://blog.astrumfutura.com/?p=372</guid>
		<description><![CDATA[Many twists and turns have been encountered since the Summer, but the online version of Zend Framework: Surviving The Deep End has escaped into the wild with the release of Chapter 1. The online book is hosted at http://www.survivethedeepend.com. Chapter 1, the Introduction, is first on the menu to open the new year. The next]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fbook-launched-zend-framework-surviving-the-deep-end%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fblog.astrumfutura.com%2F2009%2F01%2Fbook-launched-zend-framework-surviving-the-deep-end%2F&amp;source=padraicb&amp;style=normal&amp;service=bit.ly&amp;service_api=padraic%3AR_94101570b7e190f3de921bc15bb9438d&amp;hashtags=book,irishisms,php,php+general,php+security,surviving+the+deep+end,zend+framework&amp;b=2" height="61" width="50" /><br />
			</a>
		</div>
<p>Many twists and turns have been encountered since the Summer, but the online version of Zend Framework: Surviving The Deep End has escaped into the wild with the release of Chapter 1. The online book is hosted at <a href="http://www.survivethedeepend.com">http://www.survivethedeepend.com</a>.</p>
<p>Chapter 1, the Introduction, is first on the menu to open the new year. The next chapter should turn up within a few days and then we&#8217;ll see about scheduling regular chapter releases. It should be noted the new website is still a work in progress and I have a few features in testing to bring it to completion and fix some final design wishes I had, but the main feature I&#8217;m pleased to have added is an inline comment system. You may now comment on (or complain about) each paragraph individually using the jQuery powered comment system. Every paragraph has an unobstrusive link next to it showing the current number of comments for that paragraph &#8211; clicking the link shows all existing comments for that paragraph and a comment form to add another.</p>
<p>As many of you know, the book is available online without charge. If you are feeling generous in the coming weeks I am accepting donations. I promise that Steve Jobs will appreciate the gesture when I buy that new Macbook Pro <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Obviously a chunk of any donations will also vanish into the coffers of Slicehost.com where the book is being hosted on their excellent VPS offering.</p>
<p>Let me know your thoughts, and post any general comments or questions on the book or website here. I&#8217;ll be adding a general end-of-page comment system to the mix during the next day or two so posting general comments here is a temporary stopgap.</p>
<p>Huge thanks to all my readers and PHP acquaintances who kept me motivated <img src='http://blog.astrumfutura.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.astrumfutura.com/2009/01/book-launched-zend-framework-surviving-the-deep-end/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>

