<?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>Web:Extend &#187; Simplicity</title>
	<atom:link href="http://blog.extend.ws/category/simplicity/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.extend.ws</link>
	<description>Web:Extend's Development Blog</description>
	<lastBuildDate>Thu, 16 Sep 2010 20:38:15 +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>RoWO &#8211; Part 2: Simple is Easy</title>
		<link>http://blog.extend.ws/2008/11/06/rowo-part-2-simple-is-easy/</link>
		<comments>http://blog.extend.ws/2008/11/06/rowo-part-2-simple-is-easy/#comments</comments>
		<pubDate>Thu, 06 Nov 2008 11:42:36 +0000</pubDate>
		<dc:creator>Loïc Hoguin</dc:creator>
				<category><![CDATA[Optimization]]></category>
		<category><![CDATA[Simplicity]]></category>
		<category><![CDATA[Web:Extend]]></category>

		<guid isPermaLink="false">http://blog.extend.ws/?p=7</guid>
		<description><![CDATA[About two months ago, Rasmus Lerdorf gave a talk at FrOSCon entitled Simple is Hard. If you don&#8217;t know about it yet I recommend reading the slides before continuing with this article.
Rasmus proved how hard it is to stay simple when writing an application or a library, and explained that the main victims of complexity [...]]]></description>
			<content:encoded><![CDATA[<p>About two months ago, <a href="http://en.wikipedia.org/wiki/Rasmus_Lerdorf">Rasmus Lerdorf</a> gave a talk at FrOSCon entitled <a href="http://talks.php.net/show/froscon08">Simple is Hard</a>. <em>If you don&#8217;t know about it yet I recommend reading the slides before continuing with this article.</em></p>
<p>Rasmus proved how hard it is to stay simple when writing an application or a library, and explained that the main victims of complexity are scalability, performance and security. He used a good number of frameworks to prove his point, showing the overhead in performance for an &#8220;Hello world!&#8221; application along with the graph of all the included files for generating such a simple request. Of course your application will be more than just an &#8220;Hello world!&#8221; but this shows just how much is loaded by the various frameworks for doing such a simple task.</p>
<p>I found the results to be frightening. So I looked at how <em>simple</em> our framework is compared to the others.</p>
<h2>The first day</h2>
<p>After firing siege, I got a very bad result: only around 120 trans/sec when PHP alone did more than 4000 trans/sec. It wasn&#8217;t surprising however, considering no performance optimization was ever done in the project. With the project reaching beta soon, it&#8217;s time to change this and multiply the speed.</p>
<p>You can take a look at the inclued file from that day:</p>
<p><a href="http://blog.extend.ws/wp-content/uploads/2008/11/wee-yesterday.png"><img class="size-medium wp-image-41" title="wee-yesterday" src="http://blog.extend.ws/wp-content/uploads/2008/11/wee-yesterday-300x112.png" alt="Web:Extend's inclued graph, before caching" width="300" height="112" /></a></p>
<h2>Optimizations</h2>
<p>Firing up the XDebug profiler, we could observe this call graph:</p>
<p><a href="http://blog.extend.ws/wp-content/uploads/2008/11/wee-yesterday-callgraph.png"><img class="size-medium wp-image-40" title="wee-yesterday-callgraph" src="http://blog.extend.ws/wp-content/uploads/2008/11/wee-yesterday-callgraph-258x300.png" alt="Web:Extend's call graph, before caching" width="258" height="300" /></a></p>
<p>It&#8217;s easy to see what takes time&#8230; The <code>weeAutoload::addPath</code> method takes 76% of the execution time, and the configuration file loading 12%. Both can be cached and are only subject to change in a development environment or when upgrading, so we can automatically cache them when <code>DEBUG</code> mode is off and ignore the cache otherwise.</p>
<p>The cache method used is pretty simple. The cache files have no expiration time, they&#8217;re just deleted when upgrading an installation to a new version. If something goes wrong, the global constant <code>NO_CACHE</code> will happily ignore the cache files. And in development, cache is ignored as long as you have <code>DEBUG</code> enabled, which you should have all the time when developing.</p>
<p>The first time the script runs the data (an array in both case) is written to the cache file as valid PHP using <a href="http://php.net/var_export">var_export</a>. Subsequent runs will simply <a href="http://php.net/require">require</a> this file to load the cache. To prevent security problems, the file mode is set to 0600, disabling its access to anyone other than the webserver&#8217;s user.</p>
<h2>Today</h2>
<p>Using siege today I get these results:</p>
<pre>essen@karen (0) % siege -c 5 "http://localhost/wee/trunk/" -b -t30s &gt; /tmp/wee-today
** SIEGE 2.66
** Preparing 5 concurrent users for battle.
The server is now under siege...

Lifting the server siege...      done.
Transactions:		       40995 hits
Availability:		      100.00 %
Elapsed time:		       30.16 secs
Data transferred:	        3.44 MB
Response time:		        0.00 secs
Transaction rate:	     1359.25 trans/sec
Throughput:		        0.11 MB/sec
Concurrency:		        4.97
Successful transactions:       40995
Failed transactions:	           0
Longest transaction:	        0.04
Shortest transaction:	        0.00</pre>
<p>Not bad at all, considering all we did really was to cache the autoload and configuration data automatically.</p>
<p>The <em>inclued</em> graph looks like this on the first load:</p>
<p><a href="http://blog.extend.ws/wp-content/uploads/2008/10/wee-inclued-nocache.png"><img class="size-medium wp-image-19" title="wee-inclued-nocache" src="http://blog.extend.ws/wp-content/uploads/2008/10/wee-inclued-nocache-300x98.png" alt="Web:Extend's inclued graph, cache disabled" width="300" height="98" /></a></p>
<p>And like this when the cache files have been generated:</p>
<p><a href="http://blog.extend.ws/wp-content/uploads/2008/10/wee-inclued-cache.png"><img class="size-medium wp-image-23" title="wee-inclued-cache" src="http://blog.extend.ws/wp-content/uploads/2008/10/wee-inclued-cache-300x97.png" alt="Web:Extend's inclued graph, cache enabled" width="300" height="97" /></a></p>
<p>As you can probably guess, we won&#8217;t be able to improve much more on this part of Web:Extend.</p>
<h2>Comparison with other frameworks</h2>
<p>I computed a table with results from a few other frameworks. I used the same method as Rasmus used in his presentation. There&#8217;s probably a few frameworks missing, because they&#8217;re too complex, because they require me to set up a database, or because I missed them. If you would like one added to this table, feel free to give me its name and instructions on how to write an hello world page with it.</p>
<p>For those who really think an &#8220;Hello world!&#8221; proves nothing, I also added an example of Web:Extend with a few queries for comparison. The queries include an INSERT statement recording the hits in a table, along with an UPDATE statement and a SELECT statement both working on a 100K rows table. The UPDATE sets one column of one row to NOW() while the SELECT randomly selects 25 rows and display them in the template. This is not a prepared statement so it can be faster.</p>
<table style="text-align:center" border="1">
<thead>
<tr>
<th>Framework</th>
<th>without APC</th>
<th>with APC, apc.stat=1</th>
<th>with APC, apc.stat=0</th>
<th>with APC, apc.stat=0, % efficiency</th>
</tr>
</thead>
<tbody>
<tr>
<th>PHP</th>
<td>3965.53</td>
<td>4019.18</td>
<td>4018.94</td>
<td>100%</td>
</tr>
<tr>
<th>Akelos</th>
<td>20.28</td>
<td>52.40</td>
<td>52.47</td>
<td>1.3%</td>
</tr>
<tr>
<th>CakePHP</th>
<td>49.26</td>
<td>183.26</td>
<td>181.70</td>
<td>4.5%</td>
</tr>
<tr>
<th>CodeIgniter</th>
<td>224.36</td>
<td>903.99</td>
<td>940.07</td>
<td>23.4%</td>
</tr>
<tr>
<th>Kohana</th>
<td>198.60</td>
<td>596.21</td>
<td>609.00</td>
<td>15.2%</td>
</tr>
<tr style="background:#dfd">
<th>Web:Extend</th>
<td>454.13</td>
<td>1359.25</td>
<td>1344.81</td>
<td>33.5%</td>
</tr>
<tr style="background:#dfd">
<th>Web:Extend w/ queries</th>
<td>223.97</td>
<td>426.77</td>
<td>418.61</td>
<td>N/A</td>
</tr>
<tr>
<th>Zend Framework</th>
<td>53.03</td>
<td>182.11</td>
<td>234.53</td>
<td>5.8%</td>
</tr>
</tbody>
</table>
<p>Tests were done with Ubuntu&#8217;s default PHP configuration file, on Ubuntu.</p>
<p>A few notes about ZF: since it&#8217;s the only framework requiring the setting of include_path, it was tested separately with its library path configured specifically for these tests. The include_path started with the path to the library. Other tests didn&#8217;t have any modification of the configuration.</p>
<p>I was kinda surprised to see Kohana being so slow compared to CodeIgniter. As you might not know Kohana is based off CodeIgniter. Maybe there&#8217;s a reason? If you know something that could make Kohana slower than CodeIgniter, tell me and I can run the test one more time.</p>
<p>As you can see, there&#8217;s a huge difference in performance today between Web:Extend and the other frameworks. Performance-wise, if you&#8217;re running PHP5, Web:Extend is your best bet. If you&#8217;re still running PHP4, CodeIgniter will get the job done.</p>
<h2>Tomorrow</h2>
<p>There&#8217;s still a few things we want to improve in our framework in the next few weeks.</p>
<h3>Lazy-loading of the application&#8217;s modules</h3>
<p>There&#8217;s currently 3 application modules: output, database and sessions. We already do a lazy start of the output module, but not of the 2 others. This means that the application will always connect to the database, even when no query are performed. Or that the application will always start the session, even when you don&#8217;t need it. <em>Unless of course you didn&#8217;t activate these modules in the configuration file at all.</em></p>
<p>With lazy-loading of the modules, we&#8217;ll be able to connect to the database only when <code>weeApp()-&gt;db</code> is called. Or start the session only when <code>weeApp()-&gt;session</code> is called. The modules won&#8217;t be initialized at all if they&#8217;re not required for the current page.</p>
<h3>Send output to browser early</h3>
<p>Currently the framework generates the templates after the request handling ended. Sometimes you might have some heavy operations to do, like logging, saving a search result, doing some maintenance on the database that the user doesn&#8217;t care about. We&#8217;ll make it possible to send the output to the browser as soon as possible and perform these other tasks without making the user wait.</p>
<p>Jayson Minard wrote about this recently at devzone: <a href="http://devzone.zend.com/article/3884-Scaling-Day-By-Day">Do Not Make Users Wait for Things They Do Not Care About</a>.</p>
<p>It might also be interesting to <a href="http://developer.yahoo.com/performance/rules.html#flush">send parts of the page early</a>, like the header of the HTML page.</p>
<h3>Send cache early</h3>
<p>It might be possible to send cached pages directly from the <code>index.php</code> file, which would be really fast but would not be a good choice for all types of applications. We&#8217;re still not decided on this. The pros are that the file would be sent very fast, without loading the framework: it would be almost as fast as fetching an HTML file directly. The cons are that it won&#8217;t be useable for anything other than simple pages, common to every users. This would be a good choice for <em>vitrine</em> websites or any page that doesn&#8217;t require user&#8217;s input. We probably will implement it, since our current cache is already &#8220;restricted&#8221; to common pages. And for other pages the best solution is to use APC or memcache anyway.</p>
<h3>Integrate caching methods semi-transparently in the model</h3>
<p>Allow the developer to cache the results of a query without having to worry about the caching mechanism used (be it APC, memcache or anything else). The framework would choose the best available on the system and provide a standard interface directly in the model classes. For example, instead of <code>$this-&gt;query</code> you could use <code>$this-&gt;queryCache</code> to cache the query automatically, with an optional timeout value passed as parameter. You could also use <code>$this-&gt;deleteCache</code> to delete the cache corresponding to the parameters given. It could be all the cache for the current model, or only part of it. We would of course provide an option to allow you to choose the caching mechanism used in case the framework doesn&#8217;t choose the one you want.</p>
<h3>Automate scaling</h3>
<p>We saw a few days ago how we could analyze all our SELECT queries in one script. This is a functionality offered by our framework today. But this is not enough. We&#8217;re still missing a data generator that can handle relational data generation <em>(if you know a good one we could use, please leave a comment!)</em>; a builtin profiler to test queries and functions; and a tool to create reports based on the data generated by query analyze and overall benchmark. As you already saw, the analyze of the SELECT queries returns a PHP array. This wasn&#8217;t because of laziness, this was because we intend to give you a nice report of these analysis, complete with emphasis on the problematic values (at least for MySQL and PgSQL, anyway).</p>
<h2>Simplicity is a philosophy</h2>
<p>To quote <a href="http://en.wikipedia.org/wiki/Simplicity">wikipedia</a>, <em>Simplicity is the property, condition, or quality of being simple or un-combined. It often denotes beauty, purity or clarity. Simple things are usually easier to explain and understand than complicated ones. Simplicity can mean freedom from hardship, effort or confusion.</em></p>
<p>Code simplicity can be achieved by following a few rules:</p>
<ol>
<li>Define code and naming conventions and stick with it.</li>
<li>Never load what you don&#8217;t need.</li>
<li>Refactoring duplicate code is only worth it if it is used at least 3 times.</li>
<li>Use the <a href="http://php.net/manual/en/book.spl.php">Standard PHP Library</a>.</li>
<li>Use of the right tool for the job. Use SQL for querying databases, XPATH for XML files.</li>
<li>Prefer learning a technology than learning the libraries built around it.</li>
<li>Automatically cache what you can; if you can&#8217;t, provide an easy-to-use interface for caching.</li>
<li>Slow code often means high complexity.</li>
</ol>
<p>And if you ever need guidance in the path of simplicity, ask this <a href="http://en.wikipedia.org/wiki/Mahatma_Gandhi">good man</a>.</p>
<p>Thanks for reading.</p>
<p><em>Disclaimer: If you feel like exploring the framework then have fun, but remember that the documentation is still lacking and that some parts of the API may change before we reach beta. We advise you to wait for the beta release before trying to use it, unless you feel adventurous or just plain curious.</em></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.extend.ws/2008/11/06/rowo-part-2-simple-is-easy/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

