<?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/"
	>

<channel>
	<title>Chapter 42 &#187; cms</title>
	<atom:link href="http://chapter42.whitewhale.net/tag/cms/feed/" rel="self" type="application/rss+xml" />
	<link>http://chapter42.whitewhale.net</link>
	<description></description>
	<lastBuildDate>Thu, 30 Sep 2010 17:20:47 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Coding Ahead of Yourself</title>
		<link>http://chapter42.whitewhale.net/2008/11/24/coding-ahead-of-yourself/</link>
		<comments>http://chapter42.whitewhale.net/2008/11/24/coding-ahead-of-yourself/#comments</comments>
		<pubDate>Mon, 24 Nov 2008 20:41:49 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Behind the scenes]]></category>
		<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[backwards compatibility]]></category>
		<category><![CDATA[bugs]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[diagnostics]]></category>
		<category><![CDATA[livewhale]]></category>
		<category><![CDATA[lwblog]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[whitewhale]]></category>

		<guid isPermaLink="false">http://chapter42.whaleblogs.net/?p=144</guid>
		<description><![CDATA[When you&#8217;re maintaining a software product which evolves and expands in order to remain competitive and make itself more useful to a user base, it&#8217;s easy to forget to keep all the moving parts in line with changes and new features as you roll them out. However, if this issue isn&#8217;t dealt with, bugs and [...]]]></description>
			<content:encoded><![CDATA[<p>When you&#8217;re maintaining a software product which evolves and expands in order to remain competitive and make itself more useful to a user base, it&#8217;s easy to forget to keep all the moving parts in line with changes and new features as you roll them out. However, if this issue isn&#8217;t dealt with, bugs and performance issues will inevitably arise.</p>
<p><a href="http://www.livewhale.com/">LiveWhale</a>, our CMS, is essentially a module-based system. Individual modules can be provided to our customers on a per-client basis. Each module is a self-contained element, that &#8220;registers&#8221; itself in the CMS framework, thereby establishing its functionality throughout. A module is responsible for creating and managing its own data, but if it is flagged as group owned, access to that data is handled by LiveWhale&#8217;s users and groups system.<span id="more-144"></span></p>
<p>It is, of course, possible for an administrator to manage those users and groups, and should a circumstance arise in which a group should be targeted for deletion, LiveWhale automatically cleans up data associated with that group (whether it is stored in a database or the file system) so that it is not orphaned. (This is in fact the case with any piece of data which &#8220;contains&#8221; additional hierarchical data.)</p>
<p>The mechanism we have in place for this is simple, but it is also flexible. Each piece of associated data that has to be cleaned up by a parent marked for deletion can optionally be given to a handler deletion function. For example, if a piece of news stores an image in the file system, the handler function is activated to clean that up as well.</p>
<p>Eventually we added a global activity log to our CMS, LiveWhale. Activity is associated with a user and a group, making this data group owned. As it turned out, the group deletion mechanism possessed a flaw. LiveWhale&#8217;s internal delete routine initially expected the logic about what a handler function had to do, if anything, to come from the handler function itself. In fact what it needed to do was to first deduce if a handler was optimal for a particular type of data at all. The activity data made this clear, when there was suddenly a need to delete hundreds or thousands of individual pieces of data which were designed to be stored in huge quantity over a long period of time (unlike with news management, for example). Pushing the handler logic up into LiveWhale&#8217;s delete routine made it no longer necessary to perform logic a hundred or thousand times when the result was always going to be the same, and a one-off deletion procedure could alternatively be used for the bulk data.</p>
<p>This drives home the point that building something requires either the proper foresight to know how that system has to conform to conditions that haven&#8217;t yet come about, or ensuring that the foundation you&#8217;ve already built adjusts to appropriately handle new features as you add them. Fortunately, our LiveWhale development process utilizes a variety of monitoring tools and diagnostic tests which inspect the system closely to continually perform a sanity check on the results of code execution over the product&#8217;s development lifetime. This was a case where the system noticed the deletion flaw even before I did.</p>
]]></content:encoded>
			<wfw:commentRss>http://chapter42.whitewhale.net/2008/11/24/coding-ahead-of-yourself/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Optimization in PHP</title>
		<link>http://chapter42.whitewhale.net/2008/08/20/optimization-in-php/</link>
		<comments>http://chapter42.whitewhale.net/2008/08/20/optimization-in-php/#comments</comments>
		<pubDate>Wed, 20 Aug 2008 20:10:07 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Behind the scenes]]></category>
		<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[application]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[livewhale]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[speed]]></category>
		<category><![CDATA[whitewhale]]></category>

		<guid isPermaLink="false">http://chapter42.whaleblogs.net/?p=94</guid>
		<description><![CDATA[Optimization is one of the most enjoyable parts of software design, but unfortunately it does not claim a high percentage of development time. Generally speaking, it is not a task to consider until the time spent is justified, which is often toward the end of the development cycle (but not always!) Still, it is an [...]]]></description>
			<content:encoded><![CDATA[<p>Optimization is one of the most enjoyable parts of software design, but unfortunately it does not claim a high percentage of development time. Generally speaking, it is not a task to consider until the time spent is justified, which is often toward the end of the development cycle (but not always!) Still, it is an important step, especially with products like LiveWhale, which has to perform well under high traffic spikes. I&#8217;ve already talked about general page caching before, but fine-tuning a PHP application for speed when something is not cached is also important. Here are some thoughts on how to do just that.</p>
<p>At the code level, LiveWhale is a framework, which means the same codebase is hit for many different types of requests. The question is then: how to achieve high performance with a codebase that has to perform so many tasks and is therefore code heavy. It makes sense to divide code across a handful of files. The objective here is to only load libraries when you need them. A typical request will only use a tiny percentage of the entire codebase, so there&#8217;s no need to read a great deal of code from the filesystem and eat up RAM per PHP request. Also, with a modular system like LiveWhale, it is not explicitly known what modules exist that will need to be loaded. An important optimization is one where only the first request to the server has to perform logic to determine what to load. The results of this expensive operation are cached, and all subsequent LiveWhale requests enjoy dramatic savings in the module loader.<span id="more-94"></span></p>
<p>A common problem with application frameworks is that they perform two very expensive tasks with every single page load: 1) initializing a session and 2) connecting to a database. Neither of these two should be assumed. In LiveWhale, a session is started only when a component requires it. A database connection only occurs when/if the first query to it is performed. Making your application sufficiently &#8220;smart&#8221; about if and when these initializations take place will also lead to dramatic speed improvements.</p>
<p>Less is more. That means you should optimize out any hit to the file system that you can, or remove extraneous database queries. Also, be wary of OO (object oriented) slowdowns. If something doesn&#8217;t need to be a class, don&#8217;t use one. Remember that calls to an object&#8217;s method are more expensive than global function calls. The same holds true for accessing an object&#8217;s properties. An obvious optimization is done when dealing with data from a foreign server. Such content should be cached as much as possible, so that rapid hits to your site don&#8217;t rely on the performance (or availability) or an external data source. Another tip would be to use error suppression (@) sparingly. This is a known performance hit. There are a number of similar, simple tips available via a quick Google search for &#8220;php optimizations&#8221;, and there are slideshows available from PHP developers on the subject.</p>
<p>Analyze how your code operates. If you have a function that uses a lot of logic (if/then, switch), make sure you understand what the &#8220;common case&#8221; is. In other words, what&#8217;s the most likely condition that function will come across? Then determine if the function&#8217;s logic is conducive to the fastest possible result under the most common case. For example, I had a function that has to intercept a variety of XML structures and handle them in different ways. One particular XML structure (the simplest possible one) was far and away the most common case. Rather than parsing the XML with simplexml_load_string() as I do with all the chunks of XML I receive, I first do a preg_match() to determine if I have the common case. In this situation, I can immediately return a simple result and skip both the parsing of the XML and the lengthy logic that goes with performing operations with it.</p>
<p>Identify &#8220;hot&#8221; functions. Functions that are called many times, often within a loop, should get the most attention in terms of optimization. First, make sure the function should be called at all, as opposed to using inline code, otherwise you needlessly acquire function overhead. Second, move any redundant logic outside of the hot function. Perhaps the check can be performed just once before the hot code is executed. There are also situations where a function can potentially be called repeatedly and end up with the same result. It might make sense to declare a static variable inside the function, to locally cache content generated by the function. On a subsequent call, it can first check the static array to see if a result already exists, and simply return that if so. This sort of fine-grained optimization will only help when there is a significant bottleneck with a particular function, but it can make a huge difference if done wisely.</p>
<p>Lastly, use <a href="http://www.xdebug.org/" target="_blank">XDebug</a>! XDebug is your friend. Among the many things it can do, it will let you profile your PHP code and generate a report about how much time your script is taking overall and within particular functions. Here&#8217;s a mockup of the type of information it provides:</p>
<table border="1" cellspacing="0" cellpadding="4">
<tbody>
<tr>
<td>Function</td>
<td>Line(s)</td>
<td>Calls</td>
<td>Cycles</td>
<td>Time</td>
</tr>
<tr>
<td>LiveWhale-&gt;foo</td>
<td>128</td>
<td>1</td>
<td>1911</td>
<td>38.3%</td>
</tr>
<tr>
<td>LiveWhale-&gt;bar</td>
<td>40</td>
<td>1</td>
<td>854</td>
<td>17.1%</td>
</tr>
<tr>
<td>do_something</td>
<td>41</td>
<td>1</td>
<td>313</td>
<td>6.3%</td>
</tr>
<tr>
<td>do_something_else</td>
<td>218/218/218/218/218/218/218/21 &#8230;</td>
<td>15</td>
<td>252 (17)</td>
<td>5.1%</td>
</tr>
<tr>
<td>do_this</td>
<td>131</td>
<td>1</td>
<td>118</td>
<td>2.4%</td>
</tr>
<tr>
<td>do_that</td>
<td>1</td>
<td>1</td>
<td>72</td>
<td>1.4%</td>
</tr>
<tr>
<td>fast</td>
<td>886</td>
<td>1</td>
<td>58</td>
<td>1.2%</td>
</tr>
<tr>
<td>faster</td>
<td>124</td>
<td>1</td>
<td>47</td>
<td>0.9%</td>
</tr>
</tbody>
</table>
<p>In this example, the function LiveWhale-&gt;foo() clearly takes the majority of the time for this request. At 38.3% of request time for a single call, it is a good candidate for serious analysis. LiveWhale-&gt;bar() is also expensive compared to other operations, and there may be ways to make this function perform better too. The function do_something() takes 6.3% for a single call, on line 41. Another function, do_something_else(), takes nearly the same amount of time but due to the fact that it was called 15 times (at 17 CPU cycles each, so 252 cycles total). Knowing why each function takes the time that it does, and why it might be called so many times, will help you maximize the performance of your application.</p>
<p>Familiarity with what makes PHP code perform well will only lead to the best decisions being made early on, so that XDebug reveals fewer inefficiencies. In the long run, many of these tips become automatic and part of your coding style, but for the best quality, production ready code, a little bit of analysis and thought goes a long way.</p>
]]></content:encoded>
			<wfw:commentRss>http://chapter42.whitewhale.net/2008/08/20/optimization-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing LiveWhale News</title>
		<link>http://chapter42.whitewhale.net/2008/08/15/introducing-livewhale-news/</link>
		<comments>http://chapter42.whitewhale.net/2008/08/15/introducing-livewhale-news/#comments</comments>
		<pubDate>Fri, 15 Aug 2008 20:45:59 +0000</pubDate>
		<dc:creator>Donald</dc:creator>
				<category><![CDATA[Behind the scenes]]></category>
		<category><![CDATA[Best Practices]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[interface]]></category>
		<category><![CDATA[livewhale]]></category>
		<category><![CDATA[lwblog]]></category>
		<category><![CDATA[usability]]></category>

		<guid isPermaLink="false">http://chapter42.whaleblogs.net/?p=88</guid>
		<description><![CDATA[I&#8217;ve called this post &#8220;Introducing LiveWhale News&#8221; because I&#8217;ll leave &#8220;Introducing LiveWhale&#8221; to Jason. It&#8217;s that big behind-the-scenes project we&#8217;ve been hinting about for a bit, and there&#8217;s quite a lot to say.
But at the risk of stealing some thunder from that announcement, I&#8217;d like to show off something that we&#8217;ve been spending a lot [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve called this post &#8220;Introducing LiveWhale News&#8221; because I&#8217;ll leave &#8220;Introducing LiveWhale&#8221; to Jason. It&#8217;s that big behind-the-scenes project we&#8217;ve been hinting about for a bit, and there&#8217;s quite a lot to say.</p>
<p>But at the risk of stealing some thunder from that announcement, I&#8217;d like to show off something that we&#8217;ve been spending a lot of time on:<a href="http://www.whitewhale.net/wordpress/wp-content/uploads/2008/08/livewhale_news.jpg"><img class="aligncenter size-full wp-image-89" title="LiveWhale News Page" src="http://www.whitewhale.net/wordpress/wp-content/uploads/2008/08/livewhale_news.jpg" alt="LiveWhale: Edit Story" width="500" height="427" /></a></p>
<p>This is the add-a-news-story page of LiveWhale, the CMS we&#8217;ve developed as an answer to problems posed in our infamous (among our clients, anyway) <a href="http://www.whitewhale.net/content/cms.php">content management manifesto</a>. In later posts I&#8217;ll go into some detail about specific interface choices we&#8217;ve made (a personal favorite is the flowchart behind attaching images to news stories), but for now I&#8217;ll talk about what we <em>didn&#8217;t</em> do.<span id="more-88"></span></p>
<p>One of the main problems with most enterprise content management solutions is their unapproachability. A simple task like a creation of a news item can be buried by layers of menus, technical jargon, and&#8211;let&#8217;s be honest&#8211;really ugly interfaces. It&#8217;s the type of interface that savvy users master through days or weeks of training and non-savvy users end up navigating by way of post-its on the side of their monitors. But you need those weeks to worry about everything else involved in your website launch; you need that space on the side of your monitor for pictures of your kids.</p>
<p>We set out to create an interface that minimizes the distance between what the user <em>wants to accomplish </em>and what she <em>has to do</em>. This gap is huge huge in most enterprise CMSes. Adding or editing a news story is a task that every staff member at your institution understands intuitively; why does it so often feel like piecemeal data entry?</p>
<p>Making the user click &#8220;Attach resource&#8221; when she wants to add an image creates a cognitive separation where one needn&#8217;t exist. So all of our instructions and labels are in plain English. Steps like having to enter the story body on one page and the contact info on another&#8211;or burying things in menus, or presenting disparate information as visually equal&#8211;create a similarly artificial distance. That&#8217;s why our news edit page looks almost like a published news page: we want the headline to jump out at you and the image to appear at reasonable size, and we want everything that appears on the frontend to appear here.</p>
<p>By minimizing this distance between the user&#8217;s goals and the user&#8217;s processes, we think we&#8217;ve made LiveWhale a snap to use regardless of where you fall on the scale of technical knowhow. One of these days we&#8217;ll give more of a detailed tour; but, in the meantime, let us know what you think.</p>
]]></content:encoded>
			<wfw:commentRss>http://chapter42.whitewhale.net/2008/08/15/introducing-livewhale-news/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

