<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>XING Devblog</title>
	
	<link>http://devblog.xing.com</link>
	<description>Programming tidbits and other insights from the developers at XING.com</description>
	<lastBuildDate>Fri, 12 Feb 2010 14:11:31 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/XingDevblog" /><feedburner:info uri="xingdevblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>Browser caching – Why is it not a good standalone solution?</title>
		<link>http://feedproxy.google.com/~r/XingDevblog/~3/AU122dEfr44/</link>
		<comments>http://devblog.xing.com/frontend/browser-caching-why-is-it-not-a-good-standalone-solution/#comments</comments>
		<pubDate>Fri, 12 Feb 2010 13:32:53 +0000</pubDate>
		<dc:creator>Björn Kaiser</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://devblog.xing.com/?p=294</guid>
		<description><![CDATA[Also available is the ‘memory cache’, which is located in the system’s volatile main memory (RAM) and merely used to improve the surfing experience. Pages that appear in the browser history are then stored in the cache in a volatile manner (power off means loss of data). The same applies to assets from SSL connections [...]]]></description>
			<content:encoded><![CDATA[<p>Also available is the <strong>‘memory cache’</strong>, which is located in the system’s volatile main memory (RAM) and merely used to improve the surfing experience. Pages that appear in the browser history are then stored in the cache in a volatile manner (power off means loss of data). The same applies to assets from SSL connections which are not stored in the disk cache as they may pose a security risk. With Mozilla browsers the disk cache takes up 50MB by default, whereas Microsoft browsers are non-transparent in this regard, and, as expected, leave it up to the operating system to handle the memory cache.</p>
<p><span id="more-294"></span>Browsers that support HTML5 and session storage also have an <strong>‘offline disk cache’</strong>, which is comparable to a SQLite database and can be operated via JavaScript. In general, this cache is about 500MB in size and GoogleMail uses this feature in order to make the application available when offline.</p>
<p>In terms of caching, XING focuses on optimizing <strong>‘disk cache’</strong> utilization as the <strong>‘memory cache’</strong> cannot be used in a targeted manner and does not represent a sound method for cache optimizing in the long term. We therefore do not consider the specific use of offline disk caching to be effective due to a lack of general support.</p>
<h3>The ideal client caching state can be seen in the following figure:</h3>
<div class="img-left"><img src="/wp-content/uploads/ideal-state-of-a-page-request.png" alt="" width="600" height="230" /></p>
<p>Ideal state of a page request</p>
</div>
<p>As all assets are already cached by the client, no requests are sent to the server with only HTML content and tracking pixels being reloaded. At most, individual assets should be checked to ensure they are up to date by means of a 304 (not modified) request. This in turn equates to the minimum possible number of page views, i.e. minimal traffic, only the bare minimum of requests, and minimal processing time in terms of downloading time.</p>
<h3>But can this state actually be achieved in a real-life scenario?</h3>
<p>Currently, at least 50% of our PCs run Internet Explorer 8, Opera and FF2/3.x browsers, and this number is expected to rise (see following figure).</p>
<div class="img-left"><img src="http://devblog.xing.com/wp-content/uploads/percentage-distribution-of-the-top-5-browsers-in-use-at-xing.png" alt="Percentage distribution of the top 5 browsers in use at XING" width="600" height="235" /></p>
<p>Percentage distribution of the top 5 browsers in use at XING</p>
</div>
<p>In their standard delivered state, these browsers have a disk cache of 50MB (Opera 20MB). At first glance this seems to be enough as an entire page request hardly ever exceeds 500KB.</p>
<h3>However, a number of key aspects need to be taken into consideration:</h3>
<ol>
<li>Most users never clear their cache.</li>
<li>A rising number of (2.0) websites are constantly increasing in size coupled with well-documented instructions availabe for everyone in the web (e.g. Steve Souders) mean that operators are constantly having to work on squeezing as much efficiency out of user caches as possible.</li>
<li>Youtube, last.fm and other streaming stations are blowing up the cache with sometimes just one video/stream.</li>
<li>When looked at simplistically, the cache is a kind of &#8220;least recently used&#8221; (LRU) list, i.e. the files that come in and are not used for week may be dropped out, if meanwhile other files come in.</li>
<li>With some browsers, only the newer versions cache SSL content like that of xing.com (Firefox version 3.0 and above), and only if the cache header is ‘public’.</li>
</ol>
<p>The continual development of the web means that the ratio of kilobytes to page view is likely to rise, as confirmed by our in-house statistics based on the xing.com website.</p>
<div style="border: 1px solid grey;padding: 7px;font-weight: bold; font-size: 1.4em; margin-bottom: 1.2em;">An increasing amount of content and optimized caching headers (see 2. + 3.) will lead to user disk caches filling up faster than ever. When a user’s cache is full (see 1.), data from the browser are deleted that actually need to be retained.</div>
<p>A combination of the ‘total time of the file in the cache’ and ‘last use’ then determines which files are deleted first.</p>
<p>So what is the upshot of this? Most users don’t have the pleasure of fully retrieving assets from the browser cache. Instead, the assets have to be requested again from the server, which increases loading time by at least 40%. When measured precisely, the number of visitors to the site with an empty or partially empty cache is surprisingly high.</p>
<p>Our own JavaScript-based measurements showed that 45% to 62% of users had an ‘empty cache experience’ while visiting xing.com, which is a surprisingly poor value.</p>
<p>See the green line in following figure for more information.</p>
<div class="img-left"><img src="http://devblog.xing.com/wp-content/uploads/image-caching-rate-at-xing.png" alt="Image caching rate at xing.com" width="600" height="439" /></p>
<p>Image caching rate at xing.com</p>
</div>
<p>Our measurements correlate with those of a study <a href="http://yuiblog.com/blog/2007/01/04/performance-research-part-2/">conducted by Yahoo</a> which used a backend-based method and returned an ‘empty cache experience’ of around 40% to 60%.</p>
<p>Conclusion: Well-designed caching has been proven to have a positive effect on user experience and is a genuine must both now and in the future. However, this isn’t the only area we need to focus on as there are too many other factors out of our control which may rapidly lead to the entire client caching being cleared out so that the user has to download all of the assets again. To this end, strategies such as minimizing the code and modularization need to be implemented together with lazy loading. Efficient caching <strong>and</strong> minimal requests are the only combination that can guarantee positive user experience in the long term.</p>
<img src="http://feeds.feedburner.com/~r/XingDevblog/~4/AU122dEfr44" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://devblog.xing.com/frontend/browser-caching-why-is-it-not-a-good-standalone-solution/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://devblog.xing.com/frontend/browser-caching-why-is-it-not-a-good-standalone-solution/</feedburner:origLink></item>
		<item>
		<title>Prefetching</title>
		<link>http://feedproxy.google.com/~r/XingDevblog/~3/l5LFv6EALtA/</link>
		<comments>http://devblog.xing.com/frontend/prefetching/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 12:31:16 +0000</pubDate>
		<dc:creator>Björn Kaiser</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://staging.devblog.xing.com/?p=75</guid>
		<description><![CDATA[What does the browser do right after page has loaded? Nothing, nada, idlen, nichts! Meaning it waits… waits for the user to  initiate an interaction (by calling up another page, making an AJAX  request, etc.). There must be better ways to use the time. For example,  when a user types something in [...]]]></description>
			<content:encoded><![CDATA[<p>What does the browser do right after page has loaded? Nothing, nada, idlen, nichts! Meaning it waits… waits for the user to  initiate an interaction (by calling up another page, making an AJAX  request, etc.). There must be better ways to use the time. For example,  when a user types something in a search box, it&#8217;s almost a sure thing  that the next page will be a &#8220;search results&#8221; page. Or when a user  starts logging in on the xing.com landing page, it&#8217;s a safe bet that the  next page will be the logged in home page.</p>
<p><span id="more-75"></span></p>
<p>By predicting the next page we can now load certain assets into the  browser cache before they are actually needed. If the assets are then referenced via the source code of the returned page, they are then  loaded from the browser cache and not requested from the server. This  technology is best described as “anticipated preloading”. The goal is to  anticipate what the user will do next, ideally based on precise and  detailed tracking information on user behavior, and then to load static  content in advance.</p>
<h3>The success of theese measures were clear (see the orange line which shows the loading time of the users logged-in startpage):</h3>
<div class="img-left"><img src="http://devblog.xing.com/wp-content/uploads/response-time-on-xing.png" alt="Average response time on xing.com" width="405" height="288" /></p>
<p>Average response time on xing.com (green is the average time over all measurements)</p>
</div>
<p>Since October 2009, we’ve used “anticipated preloading” for all login forms. As of December 2009 we are explicitly  pre-loading graphics of the most frequently viewed pages on xing.com. By  preloading graphics that are not immediately used, we give visitors a “primed cache experience”, and we help to avoid  the problem of poor browser caching.</p>
<p>We’ve seen results improve by over 10%  since we began pre-loading.</p>
<p>Improved preloading support is  expected from Mozilla in the future.  Since Firefox Version 3.0 for http and since 3.5 for https as well, the browser offers a &#8220;prefetch tag&#8221;:</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">link</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;prefetch&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;/images/big.jpg&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></pre></div></div>

<p>The tag directs the browser to begin loading the  image specified by ’href ’ once the current page hascompletely  loaded. When the next page is called up, there is one request  necessary. Prefetching also works with complete web pages:</p>

<div class="wp_syntax"><div class="code"><pre class="html4strict" style="font-family:monospace;"><span style="color: #009900;">&lt;<span style="color: #000000; font-weight: bold;">link</span> <span style="color: #000066;">rel</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;next&quot;</span> <span style="color: #000066;">href</span><span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;2.html&quot;</span> <span style="color: #66cc66;">/</span>&gt;</span></pre></div></div>

<p>If you’re interested in learning more, please see<br />
<a href="https://developer.mozilla.org/en/Link_prefetching_FAQ" target="_blank">https://developer.mozilla.org/en/Link_prefetching_FAQ</a>.</p>
<img src="http://feeds.feedburner.com/~r/XingDevblog/~4/l5LFv6EALtA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://devblog.xing.com/frontend/prefetching/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://devblog.xing.com/frontend/prefetching/</feedburner:origLink></item>
		<item>
		<title>Alter Table Rails Plugin</title>
		<link>http://feedproxy.google.com/~r/XingDevblog/~3/90p38BDXKuQ/</link>
		<comments>http://devblog.xing.com/ruby/alter-table-rails-plugin/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 10:08:56 +0000</pubDate>
		<dc:creator>Timothy Payton</dc:creator>
				<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Ruby on Rails]]></category>

		<guid isPermaLink="false">http://devblog.xing.com/?p=188</guid>
		<description><![CDATA[We are using the Ruby on Rails framework for a lot of our website.  And during every week&#8217;s release we have migrations running on our database.  We want those migrations to be as fast as possible, to keep our site response times low and make modifications to our database as easy as possible.  As the [...]]]></description>
			<content:encoded><![CDATA[<p>We are using the <a href="http://rubyonrails.org">Ruby on Rails</a> framework for a lot of our website.  And during every week&#8217;s release we have migrations running on our database.  We want those migrations to be as fast as possible, to keep our site response times low and make modifications to our database as easy as possible.  As the size of the data grows, the migrations get slower and slower.  We began to notice over the last couple months a pattern in raw SQL we were writing to use MySQL&#8217;s native ability to run multiple alterations on a table in a single ALTER TABLE statement.  Our new alter_table plugin for Rails is intended to provide nice ruby code for creating the same raw SQL we were writing by hand.</p>
<p><span id="more-188"></span>A migration changing an existing database table &#8216;people&#8217; might look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> AlterPeopleTable <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Migration</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">up</span>
    change_column <span style="color:#ff3333; font-weight:bold;">:people</span>, <span style="color:#ff3333; font-weight:bold;">:first_name</span>, <span style="color:#ff3333; font-weight:bold;">:string</span>, <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;John&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:null</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>
    add_column <span style="color:#ff3333; font-weight:bold;">:people</span>, <span style="color:#ff3333; font-weight:bold;">:last_name</span>, <span style="color:#ff3333; font-weight:bold;">:string</span>, <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;Doe&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:null</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>
    remove_column <span style="color:#ff3333; font-weight:bold;">:people</span>, <span style="color:#ff3333; font-weight:bold;">:street</span>
    rename_column <span style="color:#ff3333; font-weight:bold;">:people</span>, <span style="color:#ff3333; font-weight:bold;">:phone</span>, <span style="color:#ff3333; font-weight:bold;">:telephone</span>
    add_index <span style="color:#ff3333; font-weight:bold;">:people</span>, <span style="color:#ff3333; font-weight:bold;">:last_name</span>
    remove_index <span style="color:#ff3333; font-weight:bold;">:people</span>, <span style="color:#ff3333; font-weight:bold;">:zip</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>Now, we see two problems with this code. First, the table name &#8216;people&#8217; has to be repeated in every line. Second, and more important, the code will lead to six separate ALTER TABLE statements being sent to the database. This will slow down the execution of the migration significantly, especially for large tables.<br />
The good news is that databases like MySQL and PostgreSQL allow an ALTER TABLE statement to contain multiple clauses, so no matter how many alterations you want to apply to a table, they can be combined into a single ALTER TABLE statement.</p>
<p>Truthfully, we were surprised Rails did not already provide this.  So, we went ahead and added an alter_table method that follows the syntax already used in Rails migrations.</p>
<p>To take advantage of that, here is how you would write the same migration using the alter_table plugin:</p>

<div class="wp_syntax"><div class="code"><pre class="ruby" style="font-family:monospace;"><span style="color:#9966CC; font-weight:bold;">class</span> AlterPeopleTable <span style="color:#006600; font-weight:bold;">&lt;</span> <span style="color:#6666ff; font-weight:bold;">ActiveRecord::Migration</span>
  <span style="color:#9966CC; font-weight:bold;">def</span> <span style="color:#0000FF; font-weight:bold;">self</span>.<span style="color:#9900CC;">up</span>
     alter_table <span style="color:#ff3333; font-weight:bold;">:people</span> <span style="color:#9966CC; font-weight:bold;">do</span> <span style="color:#006600; font-weight:bold;">|</span>t<span style="color:#006600; font-weight:bold;">|</span>
       t.<span style="color:#9900CC;">change_column</span> <span style="color:#ff3333; font-weight:bold;">:first_name</span>, <span style="color:#ff3333; font-weight:bold;">:string</span>, <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;John&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:null</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>
       t.<span style="color:#9900CC;">add_column</span> <span style="color:#ff3333; font-weight:bold;">:last_name</span>, <span style="color:#ff3333; font-weight:bold;">:string</span>, <span style="color:#ff3333; font-weight:bold;">:default</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#996600;">&quot;Doe&quot;</span>, <span style="color:#ff3333; font-weight:bold;">:null</span> <span style="color:#006600; font-weight:bold;">=&gt;</span> <span style="color:#0000FF; font-weight:bold;">false</span>
       t.<span style="color:#9900CC;">remove_column</span> <span style="color:#ff3333; font-weight:bold;">:street</span>
       t.<span style="color:#9900CC;">rename_column</span> <span style="color:#ff3333; font-weight:bold;">:phone</span>, <span style="color:#ff3333; font-weight:bold;">:telephone</span>
       t.<span style="color:#9900CC;">add_index</span> <span style="color:#ff3333; font-weight:bold;">:last_name</span>
       t.<span style="color:#9900CC;">remove_index</span> <span style="color:#ff3333; font-weight:bold;">:zip</span>
    <span style="color:#9966CC; font-weight:bold;">end</span>
  <span style="color:#9966CC; font-weight:bold;">end</span>
<span style="color:#9966CC; font-weight:bold;">end</span></pre></div></div>

<p>The produced SQL would look like this:</p>

<div class="wp_syntax"><div class="code"><pre class="sql" style="font-family:monospace;"><span style="color: #993333; font-weight: bold;">ALTER</span> <span style="color: #993333; font-weight: bold;">TABLE</span> <span style="color: #ff0000;">`people`</span>
<span style="color: #993333; font-weight: bold;">CHANGE</span> <span style="color: #ff0000;">`first_name`</span> <span style="color: #ff0000;">`first_name`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #ff0000;">'John'</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #ff0000;">`last_name`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">255</span><span style="color: #66cc66;">&#41;</span> <span style="color: #993333; font-weight: bold;">DEFAULT</span> <span style="color: #ff0000;">'Doe'</span> <span style="color: #993333; font-weight: bold;">NOT</span> <span style="color: #993333; font-weight: bold;">NULL</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">DROP</span> <span style="color: #ff0000;">`street`</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">CHANGE</span> <span style="color: #ff0000;">`phone`</span> <span style="color: #ff0000;">`telephone`</span> varchar<span style="color: #66cc66;">&#40;</span><span style="color: #cc66cc;">64</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">ADD</span> <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #ff0000;">`index_people_on_last_name`</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">`last_name`</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">,</span>
<span style="color: #993333; font-weight: bold;">DROP</span> <span style="color: #993333; font-weight: bold;">INDEX</span> <span style="color: #ff0000;">`index_people_on_zip`</span></pre></div></div>

<p>Currently the plugin only supports MySQL databases, but other database types will be added soon.</p>
<p>If you find yourself making changes to large tables in your Rails project, you should consider using the plugin.</p>
<p>The full README, including how to install and use it, and the code are here:<br />
<a href="http://github.com/xing/alter_table">http://github.com/xing/alter_table</a></p>
<img src="http://feeds.feedburner.com/~r/XingDevblog/~4/90p38BDXKuQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://devblog.xing.com/ruby/alter-table-rails-plugin/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://devblog.xing.com/ruby/alter-table-rails-plugin/</feedburner:origLink></item>
		<item>
		<title>OMG: XING uses links with rounded corners</title>
		<link>http://feedproxy.google.com/~r/XingDevblog/~3/y53JFmWJZNQ/</link>
		<comments>http://devblog.xing.com/frontend/xing-uses-links-with-rounded-corners-css3/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 13:50:20 +0000</pubDate>
		<dc:creator>Nils Lauk</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://devblog.xing.com/?p=162</guid>
		<description><![CDATA[Every week we make changes to the XING platform. Last week we 'edged' up XING a little bit.]]></description>
			<content:encoded><![CDATA[<p>While some people might ask themselves &#8211; or us &#8211; how we could put the &#8216;edge&#8217; in XING, others have already spotted the rectangular &#8216;edit&#8217; links (we call them text buttons). You can find these text-buttons on your own profile page, for example, in the Jobs section and the Company Profiles. Some users will see these text-buttons in a rectangular shape, some see them with rounded corners. Why is that?</p>
<p><span id="more-162"></span>We at XING are constantly making use of new technology and techniques. So we decided to use the CSS3 declaration &#8220;border-radius&#8221; for our text buttons. &#8220;Boring, old, I know that&#8221; you might say and you&#8217;re right &#8211; it&#8217;s not really new &#8211; although it&#8217;s not been rendered properly by all browsers up until now. What&#8217;s new, and here&#8217;s the point, that we at XING have embraced the idea, that our site doesn&#8217;t have to look the same way in every browser (also see Ingo Chao&#8217;s blog post <a href="http://blog.xing.com/2009/02/degradation-without-grace/">Degradation without grace</a>).  The text buttons are rectangular &#8211; obviously &#8211; in Microsoft Internet Explorer, because it doesn&#8217;t understand rounded corners via CSS3. Users of the newest version of Safari, Firefox and Opera (10.5) will continue to see rounded text-buttons. Not the same as last week, but they look nearly the same.</p>
<table summary="A little overview of the browers that understand the CSS3 property border-radius">
<caption>These browsers support CSS3 rounded corners</caption>
<thead>
<tr>
<th>IE 6</th>
<th>IE 7</th>
<th>IE 8</th>
<th>IE 9</th>
<th>FF 2</th>
<th>FF 3</th>
<th>Safari 4</th>
<th>Opera 10.5</th>
<th>Chrome</th>
</tr>
</thead>
<tbody>
<tr>
<td><span class="minus">not supported</span></td>
<td><span class="minus">not supported</span></td>
<td><span class="minus">not supported</span></td>
<td><span class="plus">supported</span></td>
<td><span class="plus">supported</span></td>
<td><span class="plus">supported</span></td>
<td><span class="plus">supported</span></td>
<td><span class="plus">supported</span></td>
<td><span class="plus">supported</span></td>
</tr>
</tbody>
</table>
<h3>What did the text buttons used to look like?</h3>
<p>A short time ago, we styled the links with additional HTML and background images (CSS sprites), so they look round on all corners.</p>
<div class="img-left">
<img src="http://devblog.xing.com/wp-content/uploads/old_textbuttons.png" alt="Screenshot of old XING links" width="325" height="173"  /></p>
<p>Screenshot of old XING links</p>
</div>
<p>Not only did we have to use additional (and meaningless) markup, the CSS declaration was massive as well. And here&#8217;s what the new text buttons look like today:</p>
<div class="img-left">
<img src="http://devblog.xing.com/wp-content/uploads/new_textbuttons.png" alt="Screenshot of new XING links" width="325" height="173" /></p>
<p>Screenshot of new XING links</p>
</div>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">.text-button<span style="color: #00AA00;">,</span>
<span style="color: #6666ff;">.text-button-right</span> <span style="color: #00AA00;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#d6ecea</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">border</span><span style="color: #00AA00;">:</span> <span style="color: #933;">1px</span> <span style="color: #993333;">solid</span> <span style="color: #cc00cc;">#bcd9d7</span><span style="color: #00AA00;">;</span>
   -moz-border-radius<span style="color: #00AA00;">:</span> <span style="color: #933;">7px</span><span style="color: #00AA00;">;</span>
   -webkit-border-radius<span style="color: #00AA00;">:</span> <span style="color: #933;">7px</span><span style="color: #00AA00;">;</span>
   border-radius<span style="color: #00AA00;">:</span> <span style="color: #933;">7px</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#333</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">display</span><span style="color: #00AA00;">:</span> -moz-inline-box<span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">display</span><span style="color: #00AA00;">:</span> inline-<span style="color: #993333;">block</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">font-size</span><span style="color: #00AA00;">:</span> <span style="color: #933;">11px</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">line-height</span><span style="color: #00AA00;">:</span> <span style="color: #933;">13px</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">margin</span><span style="color: #00AA00;">:</span> <span style="color: #cc66cc;">0</span> <span style="color: #933;">5px</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">padding</span><span style="color: #00AA00;">:</span> <span style="color: #cc66cc;">0</span> <span style="color: #933;">7px</span><span style="color: #00AA00;">;</span>
   <span style="color: #000000; font-weight: bold;">text-decoration</span><span style="color: #00AA00;">:</span> <span style="color: #993333;">none</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span>
&nbsp;
a<span style="color: #6666ff;">.text-button</span><span style="color: #3333ff;">:hover</span><span style="color: #00AA00;">,</span>
a<span style="color: #6666ff;">.text-button-right</span><span style="color: #3333ff;">:hover </span><span style="color: #00AA00;">&#123;</span>
   <span style="color: #000000; font-weight: bold;">background-color</span><span style="color: #00AA00;">:</span> <span style="color: #cc00cc;">#bcd9d7</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<h3>What&#8217;s the benefit in using rounded corners via CSS3?</h3>
<p>Using CSS3 to round the corners saves a lot of HTML and CSS. To demonstrate, we put the new text buttons to a test. For this we built a little page with ten old text buttons as well as a page with ten new ones. We tested the speed of the page-loading with a tiny JavaScript and were pleased with the result we achieved.</p>
<ul>
<li>The HTML code is only 60% the size of the old one</li>
<li>Because we don&#8217;t need the sprite image, we can, in the future, only have one Http-request, instead of two</li>
<li>No more unnecessary HTML equals a reduced DOM depth, now at 2 instead of 4</li>
<li>The CSS had 62 lines, now it only has 23 lines of code</li>
</ul>
<p>Comparing the old with the new CSS, it should be obvious why we decided to use the rounded corners via CSS3. The functionality of the webpage is still intact. Everyone with a &#8220;modern&#8221; browser, i.e. one that understands CSS3, will see the rounded corners, everyone else has to live with rectangular corners.</p>
<h3>Is XING trend-setting?</h3>
<p>Well, &#8216;trend-setting&#8217; might be a little bit too much, but we can say, that XING is looking forward &#8211; to the future. We use CSS for Webkit and for Mozilla browsers as well, to display rounded corners. But we also put the required <em>border-radius</em> into the CSS &#8211; without any browser-specific prefixes. By the way: Opera 10.5 will be the first browser supporting the <em>border-radius</em>.</p>
<p>And for all of you wondering why we used the <em>display: -moz-inline-box;</em> &#8211; well, more on that issue later. Come back and find out.</p>
<img src="http://feeds.feedburner.com/~r/XingDevblog/~4/y53JFmWJZNQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://devblog.xing.com/frontend/xing-uses-links-with-rounded-corners-css3/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		<feedburner:origLink>http://devblog.xing.com/frontend/xing-uses-links-with-rounded-corners-css3/</feedburner:origLink></item>
		<item>
		<title>Against IE8’s Compatibility View: from Stagnation to Standards</title>
		<link>http://feedproxy.google.com/~r/XingDevblog/~3/YZEtXJm--U0/</link>
		<comments>http://devblog.xing.com/frontend/against-ie8s-compatibility-view-from-stagnation-to-standards/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 13:56:04 +0000</pubDate>
		<dc:creator>Tobias Otte</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://staging.devblog.xing.com/?p=54</guid>
		<description><![CDATA[Compatibility View for IE8
Microsoft introduced Compatibility View for IE8 in accordance with their &#8220;Don&#8217;t break the web&#8221;-maxim. Previous versions of Internet Explorer did not follow web standards, IE&#8217;s development seemingly came to a standstill, consequently frontend engineers used an awful lot of workarounds to fix the non-standard rendering. However, IE8 follows the standards, and the [...]]]></description>
			<content:encoded><![CDATA[<h3>Compatibility View for IE8</h3>
<p>Microsoft introduced Compatibility View for IE8 in accordance with their &#8220;Don&#8217;t break the web&#8221;-maxim. Previous versions of Internet Explorer did not follow web standards, IE&#8217;s development seemingly came to a standstill, consequently frontend engineers used an awful lot of workarounds to fix the non-standard rendering. However, IE8 follows the standards, and the old workarounds caused many sites to break – hence Compatibility View. In Compatibility View, IE8 renders a page like IE7 did. This was meant as a helper for pages that were not updated <em>yet</em>.</p>
<p><span id="more-54"></span>Meanwhile, Compatibility View became a cause of stagnation: Sites will likely be slow to update their strategy, keeping IE in Compatibility View. Most big sites run their pages in Compatibility View nowadays, because &#8220;it just works&#8221; in IE7, and because the costs to re-engineer and to re-test the pages are fairly high. In contrast, the benefits of using Standards View in IE8 are not obvious; performance, of course – but you cannot measure that until you try it.</p>
<h3>Browser Mode and Document Mode</h3>
<p>There are two modes that rule Compatibility View: browser mode and document mode.</p>
<p><em>Browser mode</em> is to be set in the Compatibility View settings by the user and via a list hosted by Microsoft. This Compatibility View List is distributed via Windows Update to the IE8-client. XING used to be on the list, but was removed by Microsoft, so some users will land on XINGs platform in compatibility browser mode, some in standards browser mode. Although Microsoft doesn&#8217;t make this clear, site owners have to opt-in to standards mode because of the ever-changing Compatibility View List.</p>
<p><em>Document mode</em> can be set set by the site owner: as a meta-flag in the HTML document or as a response header by the server. XING used to set the document mode via <code>&lt;meta http-equiv="X-UA-Compatible" content="IE=7" /&gt;</code> in the HEAD section of your HTML documents.</p>
<p>For the beta-test migration to IE8 standards mode, we removed that meta tag. To set the document mode, our servers answered with a response header instead:</p>
<ul>
<li>&#8220;<code>X-UA-Compatible</code>&#8221; &#8220;<code>IE=8</code>&#8221; for XING developers and</li>
<li>&#8220;<code>X-UA-Compatible</code>&#8221; &#8220;<code>IE=EmulateIE7</code>&#8221; for all other users.</li>
</ul>
<p>This server-side switch allows for forking depending on the IP-address.</p>
<p>Again, you cannot rely on leaving the response header or meta tag unset because you cannot exactly know what Compatibility View List settings the browser is using. Users may or may not have used Windows Update recently; and a third party controls the list.</p>
<p><img class="size-full" title="IE8 Compatibility View Stats" src="http://devblog.xing.com/wp-content/uploads/ie8-compatibility-view-stats.jpg" alt="" width="426" height="197" /></p>
<p><strong>Fig.1:</strong> Analysis of IE8 browser mode set for Alexa&#8217;s Top 100 Sites (Nov. 2009). More than 50% are set via the Microsoft-hosted Compatibility View List.</p>
<p><strong>Fig. 2:</strong> Analysis of IE8 document mode set by Alexa&#8217;s Top 100 Sites (Nov. 2009). Quirks mode: Without a standards-mode-doctype. IE7-Standards: Render mode set via Response-Header, Meta-Tag, or Compatibility View List. IE8-Standards: One of the mentioned trigger or no trigger at all. Only 30% use the most standards adherence mode.</p>
<h3>Beta Test Findings</h3>
<p>Our internal beta tests revealed a couple of problems:</p>
<ul>
<li>Bug with <code>vertical-align: text-top</code> for inline elements in our transitional doctype (solution: ie8-specific workaround, since MS stated that they will not fix it for IE8)</li>
<li>Bad hyphenation in some texts:  &#8216;Nicht-\nMitglieder&#8217; becomes &#8216;Nicht\n-Mitglieder&#8217; (solution: won&#8217;t fix)</li>
<li>Prototype JavaScript library had to be updated when available (solution: update)</li>
<li>User-Agent sniffing breaks for those users that had the old Compatibility View settings. They land with an IE7-like User Agent, receive the response from the server, and proceed with a IE8 User Agent string. (Solution: User Agent sniffing on a pre-sanitized User Agent string.)</li>
</ul>
<p>&#8220;Haha. So, you are coming from IE6/7-specific workarounds and got IE8-specific workarounds in addition?&#8221; This is partly true. On the other hand, we gained a lot more standards compliance and run a comparatively small set of workarounds, with the benefit of better performance for a growing set of users who switched to IE8. More users are getting less workarounds.</p>
<h3>Performance Results</h3>
<p>Because there is no need to serve IE7-related workarounds to IE8 any more, the amount of loaded CSS rules per page decreased significantly, and we saved one HTTP-request on every page load. The page load times (Page loaded, Dom loaded, Interaction ready) are better – measured and perceived. IE8 was known to be faster than its predecessors, and we could measure it on-site, not just on laboratory conditions.</p>
<h3>Was it worth it?</h3>
<p>Yes, definitely. We stopped using a comfortable mode that meant a dead-end-street for development, and we got measurable benefits for our users.</p>
<img src="http://feeds.feedburner.com/~r/XingDevblog/~4/YZEtXJm--U0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://devblog.xing.com/frontend/against-ie8s-compatibility-view-from-stagnation-to-standards/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		<feedburner:origLink>http://devblog.xing.com/frontend/against-ie8s-compatibility-view-from-stagnation-to-standards/</feedburner:origLink></item>
		<item>
		<title>Hello World</title>
		<link>http://feedproxy.google.com/~r/XingDevblog/~3/xDsCJm2REDc/</link>
		<comments>http://devblog.xing.com/everything-else/hello-world/#comments</comments>
		<pubDate>Sat, 02 Jan 2010 09:16:56 +0000</pubDate>
		<dc:creator>Hendrik Mans</dc:creator>
				<category><![CDATA[Everything else]]></category>

		<guid isPermaLink="false">http://staging.devblog.xing.com/?p=43</guid>
		<description><![CDATA[There&#8217;s only so many ways to start the inaugural post for a new blog, so how about this: welcome to the officially official XING Developers Blog, where we &#8212; the tech geeks, developers and wizards at XING &#8212; write about our work, programming tricks we&#8217;ve learned, stuff we release to the world of open source, [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s only so many ways to start the inaugural post for a new blog, so how about this: <strong>welcome to the officially official XING Developers Blog</strong>, where we &#8212; the tech geeks, developers and wizards at <a href="http://corporate.xing.com">XING</a> &#8212; write about our work, programming tricks we&#8217;ve learned, stuff we release to the world of open source, and other random tidbits that may or may not be relevant to other developers or interested parties out there.</p>
<p>We will also be providing you with little peeks into our daily work life, which, as it turns out, is quite exciting here at <a href="http://www.xing.com">Europe&#8217;s leading business networking site</a>. We have development teams based in Hamburg and Barcelona working on new and improving existing features, and also making sure that things run as smoothly as possible, which every now and then can be an interesting challenge. Watch out for a bunch of future posts about our technical setup, how stuff is glued together, and how we keep it all running without major hiccups. You will see how developing a site like <a href="http://www.xing.com">xing.com</a> can indeed be quite an adventure &#8212; of awesome!</p>
<p>Which, of course, you&#8217;re very much invited to be part of. If you&#8217;re into stuff like <strong>Ruby on Rails</strong>, <strong>Perl</strong>, <strong>Java</strong> or <strong>JavaScript</strong>, fond of <strong>agile development</strong>, and would like to work on an established product that&#8217;s always changing and moving forward, check out our <a href="http://corporate.xing.com/english/company/careers-at-xing/">current job openings</a> &#8212; we&#8217;d love to hear from you.</p>
<p>Have a good 2010 everybody &#8212; rumors are this one&#8217;s going to be good.</p>
<img src="http://feeds.feedburner.com/~r/XingDevblog/~4/xDsCJm2REDc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://devblog.xing.com/everything-else/hello-world/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		<feedburner:origLink>http://devblog.xing.com/everything-else/hello-world/</feedburner:origLink></item>
	</channel>
</rss>
