<?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>灰色的灵魂 &#187; Tech</title>
	<atom:link href="http://www.xuwenhao.com/category/tech/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.xuwenhao.com</link>
	<description>生命如此短暂，掌握技艺却要如此长久</description>
	<lastBuildDate>Fri, 27 Jan 2012 11:23:50 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Hadoop背后的数学</title>
		<link>http://www.xuwenhao.com/2012/01/26/the-mathematics-behind-hadoop-based-systems/</link>
		<comments>http://www.xuwenhao.com/2012/01/26/the-mathematics-behind-hadoop-based-systems/#comments</comments>
		<pubDate>Thu, 26 Jan 2012 12:53:30 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[Hadoop]]></category>
		<category><![CDATA[Math]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=828</guid>
		<description><![CDATA[自从Nathan Marz同学写了那篇著名的How to beat the CAP theorem的Blog，以及Storm发布之后，俨然成为了技术界新偶像。顺着他本人的blog，翻了一下他过去几年的写的技术文章，发现老美的牛人们都爱总结，能够把技术实践提升到理论高度，然后抽象出新的设计和产品，比起我等只能每天苦逼苦逼应对实际需求的人来说，还是强出很多。我自己觉得那么多年，虽然觉得做什么都能做了，但是现在还是只能谈到模仿，做不到提炼总结和超越。 和著名的CAP的那篇Blog，Nathan Marz还有很多其他非常有料值得一读的博客，与其在国内的各种Hadoop大会上听大家泛泛而谈架构，还不如多看看老外们总结下来的技术博呢，比如这篇The mathematics behind Hadoop-based systems，比起大家简单列列机器数字来说，有价值得多。 我曾经写过，数学对于称为一名优秀的程序员是很重要的，但这不一定意味着一定要是多高深的数学。Nathan的这篇Blog用到的数学只有初中难度，但是的确写明白了我们遇到的很多Estimation以及集群数量预估的实际问题，我想一定也有很多人用hadoop但是和我们一样，对于很多机器数量或者workflow的管理是很粗放的，相信这篇blog对很多人都会有用，所以把它翻译成中文，全文如下 基于Hadoop的系统背后的数学 我希望一年之前我就知道这些。现在，根据一些简单的数学，我就可以回答： 为什么在我将处理能力翻倍之后，我的workflow的速度没有翻倍？ 为什么10%的任务失败率会导致我的运行时间上升到原来的300%？ 如果通过优化了我的workflow的运行时间的30%导致运行时间下降了80%？ 我的集群中到底需要多少机器可以满足性能和容错的需要？ 所有这些问题都可以通过这样一个简单的等式干净地回答： 运行时间(Runtime) = 额外开销(Overhead) / (1-{处理一小时数据需要的时间}) 我们很快就可以推导出这个等式。首先，让我们简单地讨论一下什么是我所说的“基于Hadoop的系统”1。Hadoop的一个常见的用例，就是通过运行一个workflow来处理来连续进入的流数据。这个工作流运行一个&#8221;while(true)&#8221;的循环，然后每个workflow的迭代，都处理自从上个迭代依赖累积的数据。 下面的这些分析的灵感可以在一个简单的示例中概括出来。假如说你有一个workflow需要运行12小时，然后它会在每个迭代中处理12个小时的数据。然后假如说你加强了这个workflow去做一些额外的分析，然后你估计你在当前的这个workflow中需要多花两个小时来处理。然后麻烦来了。你的workflow增加的运行时间可能远超过两小时。它可能增加了10个小时，100个小时，或者这个workflow可能呈螺旋式上升地在每个迭代中花费越来越多的时间知道无限。 为什么？ 问题在于，你将处理12个小时数据的workflow的运行时间增加到了14个小时。这意味着当下一次workflow运行的时候，有14小时的数据需要处理。既然下一个迭代有更多的数据，他要花费更多时间运行。这意味着下一个迭代会有更多的数据，等等。 为了确定什么时候运行时间，让我们做一些简单的算术。首先，让我们写下一个只有一个迭代的workflow的运行时间的等式 运行时间 = 额外开销 + {处理一小时数据的时间} * {多少小时的数据} 额外开销(Overhead)指的是花费在workflow上的任何常数项时间。例如，开始一个job需要的时间会计入额外开销。使用distributed cache来分发文件的时间会计入额外开销。你会把任何独立于数据规模的时间花费放到“额外开销”的分类中去。 “处理一小时数据的时间”指的是workflow中的动态时间。这是你忽视那些额外开销，花费在处理实际数据上的时间。如何一小时的数据会增加你半小时的运行时间上，这个值应该是0.5。如果一小时的数据会增加你一小时的运行时间，这是值就是2。 为了简洁，让我们把上面那个等式通过变量来重新写一下： T = O + P * H 为了确定workflow的稳定的运行时间，我们需要找到workflow的运行时间在哪个点上正好等于累积了的需要处理的数据量。为了做这个，我们可以简单地插入 T=H 来求解T: T = O [...]]]></description>
			<content:encoded><![CDATA[<p>自从<a href="http://nathanmarz.com/" target="_blank">Nathan Marz</a>同学写了那篇著名的<a href="http://nathanmarz.com/blog/how-to-beat-the-cap-theorem.html" target="_blank">How to beat the CAP theorem</a>的Blog，以及<a href="https://github.com/nathanmarz/storm" target="_blank">Storm</a>发布之后，俨然成为了技术界新偶像。顺着他本人的blog，翻了一下他过去几年的写的技术文章，发现老美的牛人们都爱总结，能够把技术实践提升到理论高度，然后抽象出新的设计和产品，比起我等只能每天苦逼苦逼应对实际需求的人来说，还是强出很多。我自己觉得那么多年，虽然觉得做什么都能做了，但是现在还是只能谈到模仿，做不到提炼总结和超越。</p>
<p>和著名的CAP的那篇Blog，Nathan Marz还有很多其他非常有料值得一读的博客，与其在国内的各种Hadoop大会上听大家泛泛而谈架构，还不如多看看老外们总结下来的技术博呢，比如这篇<a href="http://nathanmarz.com/blog/the-mathematics-behind-hadoop-based-systems.html" target="_blank">The mathematics behind Hadoop-based systems</a>，比起大家简单列列机器数字来说，有价值得多。</p>
<p>我曾经写过，<a href="http://www.xuwenhao.com/2011/02/01/how-import-is-math-for-a-programmer/" target="_blank">数学对于称为一名优秀的程序员是很重要的</a>，但这不一定意味着一定要是多高深的数学。Nathan的这篇Blog用到的数学只有初中难度，但是的确写明白了我们遇到的很多Estimation以及集群数量预估的实际问题，我想一定也有很多人用hadoop但是和我们一样，对于很多机器数量或者workflow的管理是很粗放的，相信这篇blog对很多人都会有用，所以把它翻译成中文，全文如下</p>
<hr />
<h2><a href="http://nathanmarz.com/blog/the-mathematics-behind-hadoop-based-systems.html" target="_blank">基于Hadoop的系统背后的数学</a></h2>
<p>我希望一年之前我就知道这些。现在，根据一些简单的数学，我就可以回答：</p>
<ul>
<li>为什么在我将处理能力翻倍之后，我的workflow的速度没有翻倍？</li>
<li>为什么10%的任务失败率会导致我的运行时间上升到原来的300%？</li>
<li>如果通过优化了我的workflow的运行时间的30%导致运行时间下降了80%？</li>
<li>我的集群中到底需要多少机器可以满足性能和容错的需要？</li>
</ul>
<p>所有这些问题都可以通过这样一个简单的等式干净地回答：</p>
<pre>
运行时间(Runtime) = 额外开销(Overhead) / (1-{处理一小时数据需要的时间})
</pre>
<p>我们很快就可以推导出这个等式。首先，让我们简单地讨论一下什么是我所说的“基于Hadoop的系统”<sup><a href="#sup1">1</a></sup>。Hadoop的一个常见的用例，就是通过运行一个workflow来处理来连续进入的流数据。这个工作流运行一个&#8221;while(true)&#8221;的循环，然后每个workflow的迭代，都处理自从上个迭代依赖累积的数据。</p>
<p>下面的这些分析的灵感可以在一个简单的示例中概括出来。假如说你有一个workflow需要运行12小时，然后它会在每个迭代中处理12个小时的数据。然后假如说你加强了这个workflow去做一些额外的分析，然后你估计你在当前的这个workflow中需要多花两个小时来处理。然后麻烦来了。你的workflow增加的运行时间可能远超过两小时。它可能增加了10个小时，100个小时，或者这个workflow可能呈螺旋式上升地在每个迭代中花费越来越多的时间知道无限。</p>
<p>为什么？</p>
<p>问题在于，你将处理12个小时数据的workflow的运行时间增加到了14个小时。这意味着当下一次workflow运行的时候，有14小时的数据需要处理。既然下一个迭代有更多的数据，他要花费更多时间运行。这意味着下一个迭代会有<strong>更多</strong>的数据，等等。</p>
<p>为了确定什么时候运行时间，让我们做一些简单的算术。首先，让我们写下一个只有一个迭代的workflow的运行时间的等式</p>
<pre>
运行时间 = 额外开销 + {处理一小时数据的时间} * {多少小时的数据}
</pre>
<p>额外开销(Overhead)指的是花费在workflow上的任何常数项时间。例如，开始一个job需要的时间会计入额外开销。使用distributed cache来分发文件的时间会计入额外开销。你会把任何独立于数据规模的时间花费放到“额外开销”的分类中去。</p>
<p>“处理一小时数据的时间”指的是workflow中的动态时间。这是你忽视那些额外开销，花费在处理实际数据上的时间。如何一小时的数据会增加你半小时的运行时间上，这个值应该是0.5。如果一小时的数据会增加你一小时的运行时间，这是值就是2。</p>
<p>为了简洁，让我们把上面那个等式通过变量来重新写一下：</p>
<pre>
T = O + P * H
</pre>
<p>为了确定workflow的稳定的运行时间，我们需要找到workflow的运行时间在哪个点上正好等于累积了的需要处理的数据量。为了做这个，我们可以简单地插入 T=H 来求解T:</p>
<pre>
T = O + P * T
T = O / (1 - P)
</pre>
<p>这就是我之前展示的等式。你可以看到，一个workflow的稳定的运行时间是和workflow中的额外开销呈线性比例的。所以如果你可以将额外开销减少25%，那么你的workflow运行时间就会减少25%。然而，一个workflow的稳定运行时间和动态处理的速率“P”不是呈线性比例的。这背后的隐含含义就是每为集群加入一台机器带来的性能提升是在减少的。</p>
<p>通过这个等式，我们可以回答我在文章开始时候写下的问题了。让我们一起来过一些这些问题：</p>
<h3>为什么在我将处理能力翻倍之后，我的workflow的速度没有翻倍？</h3>
<p>将你的机器数翻倍，会将你的“处理一小时数据需要的时间”减少50%<sup><a href="#sup2">2</a></sup>。这个的效果和你的运行时间的关系是完全依赖于之前的P值的。让我们用数学来展示一下。假如说你的workflow在集群的机器数量翻倍之前的运行时间是“T1”，翻倍之后是“T2”。这给了我们两个等式：</p>
<pre>
T1 = O / (1-P)
T2 = O / (1 - P/2)
</pre>
<p>那么性能加速就会是 T2/T2，新的运行时间和旧的运行时间的比值。这给到我们</p>
<pre>
T2 / T1 = (1 - P) / (1 - P/2)
T2 / T1 = 1 - P / (2 - P)
</pre>
<p>对这个式子作图，我们可以得到如下的图，其中原始的P在x轴上，性能加速在y轴<sup><a href="#sup3">3</a></sup>上：</p>
<p><img src="http://s3.media.squarespace.com/production/621062/7280691/blog/wp-content/uploads/2009/12/Screen-shot-2009-12-27-at-5.06.54-PM1.png" alt="" /></p>
<p>这个图说明了一切。如果你的P非常高，比如说，需要54分钟来处理一小时的数据，那么将你的集群数量翻倍会使得你新的运行时间是原来的18%，足足有82%的性能加速！这是一个非常违背直觉的结论 —— 我强烈推荐读者们仔细思考这种情况出现的背后的机制。</p>
<p>然后，如果你之前的P没有那么高（例如，需要6分钟的动态运行时间来处理1小时的数据），那么将集群数量翻倍对于运行时间几乎没有效果 —— 可能只有类似6%。由于运行时间被额外开销所主导，这是很合乎情理的，动态运行时间在运行时间中占得很小。</p>
<h3>为什么10%的任务失败率会导致我的运行时间上升到原来的300%？</h3>
<p>这个问题解释了<strong>workflow稳定性</strong>的属性。在一个大集群中，你总是会有不同的机器故障，所以任务失败率的峰值不会干掉mission critical系统的性能是非常重要的。关于这个问题的分析会和上一个问题看起来非常相似，除了我们会将动态运行时间变差而不是提高它之外。10%的任务失败率意味着我们需要多运行11%的任务来处理完我们的数据<sup><a href="#sup4">4</a></sup>。由于任务依赖于我们所拥有的数据量，这意味着，我们的“处理一小时数据需要的时间”会上升11%。类似于上一个问题，让我们将T1作为没有任务失败所需要的运行时间，T2作为有任务失败的运行时间</p>
<pre>
T1 = O / (1 - P)
T2 = O / (1 - 1.11*P)
T2 / T1 = (1 - P) / (1 - 1.11*P)
</pre>
<p>对此作图，我们得到：</p>
<p><img src="http://s3.media.squarespace.com/production/621062/7280691/blog/wp-content/uploads/2009/12/Screen-shot-2009-12-27-at-5.34.41-PM.png" alt="" width="95%" /></p>
<p><small><br />
(译著: 上图中X轴为P值，Y轴为花费时间增加的比例)<br />
</small></p>
<p>你可以看到，任务失败对于运行时间的影响在你的集群有“额外容量”减少的情况下戏剧性地增长。所以让保持你的P低是非常重要的。我们可以看到你的P越高，由于任务失败率的增加，你就更有可能进入“毁灭循环”的风险<sup><a href="#sup5">5</a></sup>。</p>
<h3>如果通过优化掉我的workflow的运行时间的30%而导致运行时间下降了80%？</h3>
<p>这个问题是使得我真正找出workflow的运行时间的模型。我曾在一个workflow中有一个荒谬的瓶颈，导致了大概10小时的额外开销<sup><a href="sup6">6</a></sup>，然后整个workflow的运行时间大概是30小时。在我优化了这个瓶颈(大约占据了30%的运行时间)之后，运行时间像石头一样坠落，最终稳定在6小时(减少了80%)。使用我们的模型，我们可以确定为什么这发生了：</p>
<pre>
30 = O / (1 - P)
6 = (O - 10) / (1 - P)
O = 12.5, P = 0.58
</pre>
<p>所以那10小时，占据了workflow中的80%的额外开销，这解释了整个的性能提升。</p>
<h3>我的集群中到底需要多少机器可以满足性能和容错的需要？</h3>
<p>这基本上是一个费效比分析的练习。我们可以看到，通过增加集群中机器数据来提高性能到回报在减少，而一旦P(“处理一小时数据需要的时间”)下降到30分钟以下(0.5)，通过增加机器获得的性能提升是次线性的<sup><a href="#sup7">7</a></sup>。我们也同样看到将P保持得低是很重要得，不然任务失败的增加或者其他的任务使用集群，会严重影响你的运行时间。所以，你需要运行一些数据来确定对你的应用最佳的机器数量<sup><a href="#sup8">8</a></sup>。</p>
<p>你应该在Twitter上follow<a href="http://twitter.com/nathanmarz" target="_blank">我</a>。</p>
<p>更新：看看<a href="http://nathanmarz.com/blog/hadoop-math-followup-measurement/" target="_blank">本文的后续内容</a></p>
<hr />
<p><small><br />
<sup id="sup1">1</sup> 事实上，这个等式适用于任何批量处理连续数据流的系统。<br />
<sup id="sup2">2</sup> 这里假设你的处理是完全分布式的，并且没有持有任何中心点，这对于一个基于Hadoop的workflow来说通常是真的。一个可能的例外是，你所有的tasks都通过一个中心的数据库进行通信。事实上，增加更多的机器会在额外开销(更多的机器去处理)以及数据处理速率(mapper需要将数据分发到更多的reducer中去)有少量的不利影响。对于这个分析的目的来说，我们可以忽略这些。<br />
<sup id="sup3">3</sup> 该图通过<a href="http://www.fooplot.com/" target="_blank">FooPlot</a>生成。<br />
<sup id="sup4">4</sup> 比如说我们通过100个task来处理数据，现在，当你运行这些task的时候，其中有10个会失败。当你重新运行这10个的时候，9个会成功，还有1一个会失败。所以你实际运行了111个task而不是100个，这意味着task的数量增加了11%。<br />
<sup id="sup5">5</sup> 或者其他的运行在集群上的东西，比如一次性的查询或者其他的workflow。<br />
<sup id="sup6">6</sup> 这是由于Berkeley DB在ext3的文件系统上会生成很多碎片。<br />
<sup id="sup7">7</sup> 事实上，我没有展示这个，但是你可以通过模型来自己推导。我把这个作为一个练习留给读者。<br />
<sup id="sup8">8</sup> 如果你需要的话，你可以让这个模型变得更加全面。比如，这个模型没有区分新进入的数据和已经存在需要被查询的数据(并且在每个迭代中都会增加)。这个变量必然会影响到你的长期扩展需求，记住它是非常重要的。对于那些知识对于这些workflow的性能有获得一个直觉的目的来说，这不是必须的。<br />
</small> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2012/01/26/the-mathematics-behind-hadoop-based-systems/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>运营一个系统比开发一个系统更重要</title>
		<link>http://www.xuwenhao.com/2012/01/22/operate-a-system-is-more-important-than-develop-a-syste/</link>
		<comments>http://www.xuwenhao.com/2012/01/22/operate-a-system-is-more-important-than-develop-a-syste/#comments</comments>
		<pubDate>Sun, 22 Jan 2012 04:21:36 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[quora]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=815</guid>
		<description><![CDATA[互联网公司和软件公司最大的不同在于，即使对于技术团队来说，开发工作也只是一小部分工作，如何使得整个系统运营起来，才是重头戏，这是过去一年感悟最深的一点；而对于像广告质量这样的技术团队来说，运营和开发可以说是完全不可分离的。过去一年，在这点上，走了很多弯路，犯了很多错误，有很多可以总结的地方。从Quora上看到这样一个问题，“What are the keys to operationalizing a machine learning ranking system from an organization / engineering management point of view?” 觉得唯一的一个回答就很好，翻译一下以记之，虽然做不到信达雅，但是基本意思应该能描述对。 这个问题的大概内容是这样的: 如果从组织管理/工程管理的角度来看，什么是将一个机器学习的Ranking系统运营起来的关键点？ 对于那些有基于机器学习或者其他方式有Ranking系统的组织，可以保证他们运行平稳，并且随着时间的推移慢慢进步？哪些监控是重要的？如何定义目标，目标由谁来定义？如何分辨效果的提升来自于Feature工程团队还是核心算法上的提升？哪些严重依赖于Ranking的组织如何为这些来构造他们的流程? 目前唯一可见的回答，来自前Google的工程师Brandon Ballinger: 我之前在Google做语音识别和广告，这两者都以机器学习作为他们的核心。下面是我从“野外”学到的如何运营一个机器学习系统的一些重要的经验和教训 将你的成功的指标定义为让用户高兴。传统的精确性的指标，比如precision, square error, ROC等等并不能捕捉到那些你真正关心的——用户对于你的模型是如何反应的。例如，如果你运营一个广告系统，你的指标应该是每个PV的收入以及点击率。完全有可能，由于辛普森悖论，你有一个error rate减少了的模型，但是他带来的收入却降低了。 核心指标下降是很严重的问题。你需要把核心指标的大幅下降当成和一个服务器当机或者数据库中数据损坏一样严重的问题。Oncall的人需要尝试尽快诊断问题，并且必要时把别人拉进来一起解决问题 对每次Model的Launch做A/B测试。你应当始终并行运行两个模型，给不同的用于用不同的模型，然后比较用户行为。这是唯一可以确保你知道你在做正确的事情的办法。 小心丑小鸭效应。机器学习系统会在从自己的错误中学习的过程中变得更加准确。这意味着，新的模型有一个与生固来的缺陷：你的历史训练数据包含着过去模型中的错误，但不是你新训练的模型的错误。导致你的新模型一开始可能像一个丑小鸭，但是如果你用他来决策用户看到的内容，他最后会变成一个漂亮的天鹅。你可以通过将一小部分流量切给新模型，来部分抵消丑小鸭效应，然后慢慢随时间提高这个百分比。 使得算法对于噪声Feature健壮。类似于L1 regularization这样的技术可以使得你的机器学习算法对Feature进行剪枝，修剪掉那些对于预测的准确性贡献很小的Feature。这可以帮助你很好地拆分你的团队：一些人专注于算法，另一些人写Feature喂给算法。那些寻找Feature的人，可以直接“把东西扔进锅里”，然后让算法找出他们究竟好还是不好。（类似的，你应该通过确保合理的收敛性来选择一个算法） 你可以部分地将架构和算法团队解耦合。基本上，大部分机器学习算法都是在累计一个分布式的hash table的统计信息，然后将这些统计信息合并成一个分数。开发一个分布式的hash table是和开发一个用于累计的算法不同的任务，可以由不同的子Team完成。然后，让这些人一起工作仍然是很重要的。例如，一些算法在写入和写入可用之前延时的“最终一致”的系统中（例如Dynamo），会有所波动。所以这只是一个部分解耦合，你仍然需要团队中有连接架构和算法的“桥梁”人员。 在在线系统和批处理系统之间选择的时候要小心。一个在线系统可以实时学习，对于新的用户行为，可以在发生之后的几分钟内有所反应。但是这回带来巨大的开销，一个在线系统需要2-3倍的时间区开发和维护，而且他对瞬间的变化更加敏感。举个例子，如果你突然接收到了很多垃圾信息，这些噪声会立刻被吸收进你的系统并且开始降低用户的体验。类似的，一台机器如果没有可运行的内容了，如果网络连接中断了，或者一个特定的机器变慢了（导致Feature“歪了”），模型的某个输入开始生产垃圾，等等。 为所有东西打上版本。一个训练过的模型依赖于稳定的标识，如果你更改了某个标识，模型立刻就过时了。例如，如果你将用户的语言(&#8220;en-us&#8221;)作为一个feature。那么当有些人提交了一个一行的修改，用下划线替换了短横线(&#8220;en_us&#8221;)。这使得模型立刻“忘记”了所有从&#8221;en-us&#8221;中学到的，使得所有的语言看起来都是一样的。所以为所有会在你模型中生成标识的代码和数据的变更都打上版本。 你需要咬碎100-1000倍于实时的数据。如果你的训练数据来自于整整一年的历史数据，然后你的学习过程是10倍于实时，那他需要一个月来测试一个新Feature。把所有的东西都写成Map-Reduce或者Storm Topology使得你可以在数据变得足够大的时候仍然可以扩展。 看了一下，里面有不少错误我们都犯过，包括过去一个Q我们觉得由于团队小应该快点冲而省略掉的东西，现在看来也还是省略不掉的，而之前做对的部分也都是来自老大们的经验，希望今年少走弯路效果好啊。]]></description>
			<content:encoded><![CDATA[<p>互联网公司和软件公司最大的不同在于，即使对于技术团队来说，开发工作也只是一小部分工作，如何使得整个系统运营起来，才是重头戏，这是过去一年感悟最深的一点；而对于像广告质量这样的技术团队来说，运营和开发可以说是完全不可分离的。过去一年，在这点上，走了很多弯路，犯了很多错误，有很多可以总结的地方。从Quora上看到这样一个问题，<a href="http://www.quora.com/What-are-the-keys-to-operationalizing-a-machine-learning-ranking-system-from-an-organization-engineering-management-point-of-view" target="_blank">“What are the keys to operationalizing a machine learning ranking system from an organization / engineering management point of view?”</a></p>
<p>觉得唯一的一个回答就很好，翻译一下以记之，虽然做不到信达雅，但是基本意思应该能描述对。</p>
<p>这个问题的大概内容是这样的:</p>
<hr />
如果从组织管理/工程管理的角度来看，什么是将一个机器学习的Ranking系统运营起来的关键点？<br />
对于那些有基于机器学习或者其他方式有Ranking系统的组织，可以保证他们运行平稳，并且随着时间的推移慢慢进步？哪些监控是重要的？如何定义目标，目标由谁来定义？如何分辨效果的提升来自于Feature工程团队还是核心算法上的提升？哪些严重依赖于Ranking的组织如何为这些来构造他们的流程?</p>
<hr />
目前唯一可见的回答，来自前Google的工程师<a href="http://www.quora.com/Brandon-Ballinger" target="_blank">Brandon Ballinger</a>:</p>
<hr />
我之前在Google做语音识别和广告，这两者都以机器学习作为他们的核心。下面是我从“野外”学到的如何运营一个机器学习系统的一些重要的经验和教训</p>
<ul>
<li><strong>将你的成功的指标定义为让用户高兴。</strong>传统的精确性的指标，比如precision, square error, ROC等等并不能捕捉到那些你真正关心的——用户对于你的模型是如何反应的。例如，如果你运营一个广告系统，你的指标应该是每个PV的收入以及点击率。完全有可能，由于<a href="http://en.wikipedia.org/wiki/Simpson's_paradox" target="_blank">辛普森悖论</a>，你有一个error rate减少了的模型，但是他带来的收入却降低了。</li>
<li><strong>核心指标下降是很严重的问题。</strong>你需要把核心指标的大幅下降当成和一个服务器当机或者数据库中数据损坏一样严重的问题。Oncall的人需要尝试尽快诊断问题，并且必要时把别人拉进来一起解决问题</li>
<li><strong>对每次Model的Launch做A/B测试。</strong>你应当始终并行运行两个模型，给不同的用于用不同的模型，然后比较用户行为。这是唯一可以确保你知道你在做正确的事情的办法。</li>
<li><strong>小心丑小鸭效应。</strong>机器学习系统会在从自己的错误中学习的过程中变得更加准确。这意味着，新的模型有一个与生固来的缺陷：你的历史训练数据包含着过去模型中的错误，但不是你新训练的模型的错误。导致你的新模型一开始可能像一个丑小鸭，但是如果你用他来决策用户看到的内容，他最后会变成一个漂亮的天鹅。你可以通过将一小部分流量切给新模型，来部分抵消丑小鸭效应，然后慢慢随时间提高这个百分比。</li>
<li><strong>使得算法对于噪声Feature健壮。</strong>类似于L1 regularization这样的技术可以使得你的机器学习算法对Feature进行剪枝，修剪掉那些对于预测的准确性贡献很小的Feature。这可以帮助你很好地拆分你的团队：一些人专注于算法，另一些人写Feature喂给算法。那些寻找Feature的人，可以直接“把东西扔进锅里”，然后让算法找出他们究竟好还是不好。（类似的，你应该通过确保合理的收敛性来选择一个算法）</li>
<li><strong>你可以部分地将架构和算法团队解耦合。</strong>基本上，大部分机器学习算法都是在累计一个分布式的hash table的统计信息，然后将这些统计信息合并成一个分数。开发一个分布式的hash table是和开发一个用于累计的算法不同的任务，可以由不同的子Team完成。然后，让这些人一起工作仍然是很重要的。例如，一些算法在写入和写入可用之前延时的“最终一致”的系统中（例如Dynamo），会有所波动。所以这只是一个部分解耦合，你仍然需要团队中有连接架构和算法的“桥梁”人员。</li>
<li><strong>在在线系统和批处理系统之间选择的时候要小心。</strong>一个在线系统可以实时学习，对于新的用户行为，可以在发生之后的几分钟内有所反应。但是这回带来巨大的开销，一个在线系统需要2-3倍的时间区开发和维护，而且他对瞬间的变化更加敏感。举个例子，如果你突然接收到了很多垃圾信息，这些噪声会立刻被吸收进你的系统并且开始降低用户的体验。类似的，一台机器如果没有可运行的内容了，如果网络连接中断了，或者一个特定的机器变慢了（导致Feature“歪了”），模型的某个输入开始生产垃圾，等等。</li>
<li><strong>为所有东西打上版本。</strong>一个训练过的模型依赖于稳定的标识，如果你更改了某个标识，模型立刻就过时了。例如，如果你将用户的语言(&#8220;en-us&#8221;)作为一个feature。那么当有些人提交了一个一行的修改，用下划线替换了短横线(&#8220;en_us&#8221;)。这使得模型立刻“忘记”了所有从&#8221;en-us&#8221;中学到的，使得所有的语言看起来都是一样的。所以为所有会在你模型中生成标识的代码和数据的变更都打上版本。</li>
<li><strong>你需要咬碎100-1000倍于实时的数据。</strong>如果你的训练数据来自于整整一年的历史数据，然后你的学习过程是10倍于实时，那他需要一个月来测试一个新Feature。把所有的东西都写成Map-Reduce或者Storm Topology使得你可以在数据变得足够大的时候仍然可以扩展。</li>
</ul>
<hr />
<p>看了一下，里面有不少错误我们都犯过，包括过去一个Q我们觉得由于团队小应该快点冲而省略掉的东西，现在看来也还是省略不掉的，而之前做对的部分也都是来自老大们的经验，希望今年少走弯路效果好啊。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2012/01/22/operate-a-system-is-more-important-than-develop-a-syste/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>支持Ruby1.9的MRToolkit</title>
		<link>http://www.xuwenhao.com/2011/03/25/make-mrtoolkit-support-ruby19/</link>
		<comments>http://www.xuwenhao.com/2011/03/25/make-mrtoolkit-support-ruby19/#comments</comments>
		<pubDate>Fri, 25 Mar 2011 15:20:54 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[MapReduce]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=791</guid>
		<description><![CDATA[虽然最近的工作整天用Java写各类数据处理代码，但是去年大半年用惯了Ruby的我每每要写个测试或者临时计算的MapReduce都觉得真是太麻烦了，于是又念叨起Ruby的好来了。 先看了看利用Hadoop Streaming和Ruby来写MapReduce，发现还是有些麻烦，一是mapper和reducer要分开两个文件，二是每个任务都要重复写从stdin读取数据解析，以及输出的代码，一点不符合DRY原则，于是就找到了mrtoolkit，然后一连串杯具开始发生了。 麻烦LJ同学先给所有的机器装了Ruby1.9，然后一跑，杯具地发现没跑起来，然后发现部分代码不兼容1.9……好吧，反正没多少源代码，改之，再跑，发现虽然每台机器都下载了mrtoolkit而且都设好了RUBYLIB但还是没能成功require mrtoolkit；于是，上github抄了个别人更改的mrtoolkit版本的gemspec和Rakefile，然后打包成gem，然后安装，于是MapReduce任务在各个node上跑起来了，但是，有一部分失败了，杯具地发现Ruby1.9开始对于字符串encoding有了很多限制，使用split通过正则分割字符串的时候居然还检查整个字符串的encoding的合法性，而我们要处理的日志里会存在GBK和UTF-8混在一行编码的可能性……试了好多种方法都不行，只好再跑到邮件组上去问，得高人指点先把字符串转成BINARY的encoding进行分割，然后再转回来，终于……能用了。 所以现在就有了这个支持Ruby1.9的mrtoolkit的版本啦，首个release包含以下变更： 支持Ruby1.9 将hadoop streaming中deprecated的-jobconf参数改成了-D 单行的文本编码可以是混合编码的不合法的Ruby1.9的字符串 可以打包成gem安装(抄袭自jashmenn的版本) 还准备做个小改动是默认output目录存在时输出警告，并且不提交任务不删除输出目录，直接删除现有的输出目录这种方法太容易搞出事情来了。]]></description>
			<content:encoded><![CDATA[<p>虽然最近的工作整天用Java写各类数据处理代码，但是去年大半年用惯了Ruby的我每每要写个测试或者临时计算的MapReduce都觉得真是太麻烦了，于是又念叨起Ruby的好来了。</p>
<p>先看了看利用Hadoop Streaming和Ruby来写MapReduce，发现还是有些麻烦，一是mapper和reducer要分开两个文件，二是每个任务都要重复写从stdin读取数据解析，以及输出的代码，一点不符合DRY原则，于是就找到了<a href="http://code.google.com/p/mrtoolkit/">mrtoolkit</a>，然后一连串杯具开始发生了。</p>
<p>麻烦LJ同学先给所有的机器装了Ruby1.9，然后一跑，杯具地发现没跑起来，然后发现部分代码不兼容1.9……好吧，反正没多少源代码，改之，再跑，发现虽然每台机器都下载了mrtoolkit而且都设好了RUBYLIB但还是没能成功require mrtoolkit；于是，上github抄了个<a href="https://github.com/jashmenn/mrtoolkit">别人更改的mrtoolkit版本的gemspec和Rakefile</a>，然后打包成gem，然后安装，于是MapReduce任务在各个node上跑起来了，但是，有一部分失败了，杯具地发现Ruby1.9开始对于字符串encoding有了很多限制，使用split通过正则分割字符串的时候居然还检查整个字符串的encoding的合法性，而我们要处理的日志里会存在GBK和UTF-8混在一行编码的可能性……试了好多种方法都不行，只好再跑到邮件组上去问，得高人指点先把字符串转成BINARY的encoding进行分割，然后再转回来，终于……能用了。</p>
<p>所以现在就有了这个<a href="https://github.com/xuwenhao/mrtoolkit">支持Ruby1.9的mrtoolkit</a>的版本啦，首个release包含以下变更：</p>
<ul>
<li>支持Ruby1.9</li>
<li>将hadoop streaming中deprecated的-jobconf参数改成了-D</li>
<li>单行的文本编码可以是混合编码的不合法的Ruby1.9的字符串</li>
<li>可以打包成gem安装(抄袭自jashmenn的版本)</li>
</ul>
<p>还准备做个小改动是默认output目录存在时输出警告，并且不提交任务不删除输出目录，直接删除现有的输出目录这种方法太容易搞出事情来了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2011/03/25/make-mrtoolkit-support-ruby19/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>建议的程序员学习LDA算法的步骤</title>
		<link>http://www.xuwenhao.com/2011/03/20/suggestions-for-programmers-to-learn-lda/</link>
		<comments>http://www.xuwenhao.com/2011/03/20/suggestions-for-programmers-to-learn-lda/#comments</comments>
		<pubDate>Sun, 20 Mar 2011 04:37:52 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[LDA]]></category>
		<category><![CDATA[Machine Learning]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=785</guid>
		<description><![CDATA[这一阵为了工作上的关系，花了点时间学习了一下LDA算法，说实话，对于我这个学CS而非学数学的人来说，除了集体智慧编程这本书之外基本没怎么看过机器学习的人来说，一开始还真是摸不太到门道，前前后后快要四个月了，算是基本了解了这个算法的实现，记录一下，也供后来人快速入门做个参考。 一开始直接就下了Blei的原始的那篇论文来看，但是看了个开头就被Dirichlet分布和几个数学公式打倒，然后因为专心在写项目中的具体的代码，也就先放下了。但是因为发现完全忘记了本科学的概率和统计的内容，只好回头去看大学时候概率论的教材，发现早不知道借给谁了，于是上网买了本，花了几天时间大致回顾了一遍概率论的知识，什么贝叶斯全概率公式，正态分布，二项分布之类的。 后来晚上没事儿的时候，去水木的AI版转了转，了解到了Machine Learning的圣经PRML，考虑到反正也是要长期学习了，搞了电子版，同时上淘宝买了个打印胶装的版本。春节里每天晚上看一点儿，扫了一下前两章，再次回顾了一下基本数学知识，然后了解了下贝叶斯学派那种采用共轭先验来建模的方式。于是再次尝试回头去看Blei的那篇论文，发现还是看不太懂，于是又放下了。然后某天Tony让我准备准备给复旦的同学们share一下我们项目中LDA的使用，为了不露怯，又去翻论文，正好看到Science上这篇Topic Models Vs. Unstructured Data的科普性质的文章，翻了一遍之后，再去PRML里看了一遍Graphic Models那一张，觉得对于LDA想解决的问题和方法了解了更清楚了。之后从search engine里搜到这篇文章，然后根据推荐读了一部分的Gibbs Sampling for the Uninitiated。之后忘了怎么又搜到了Mark Steyvers和Tom Griffiths合著的Probabilistic Topic Models，在某个周末往返北京的飞机上读完了，觉得基本上模型训练过程也明白了。再之后就是读了一下这个最简版的LDA Gibbs Sampling的实现，再回过头读了一下PLDA的源码，基本上算是对LDA有了个相对清楚的了解。 这样前前后后，也过去了三个月，其实不少时间都是浪费掉的，比如Blei的论文在没有任何相关知识的情况下一开始读了好几次，都没读完而且得到到信息也很有限，如果重新总结一下，我觉得对于我们这些门外汉程序员来说，想了解LDA大概需要这些知识: 有基本的概率论的知识，这个拿个大学的课本大概翻一下就好了 PRML的前两章和Graphic Model那部分需要浏览一下，了解一下所谓的贝叶斯学派的方法论，然后理解共轭先验的概念，以及Graphic Model的图形表达的意思。 了解一下Gibbs Sampling的概念 直接读Steyvers的Probabilistic Topic Models，没必要一定去读Blei的论文，开创性的论文不一定好读，最典型的例子就是Paxos了，30多页里多少都是希腊人名，对于英文不够精通，学术训练比较少的工程师来说，其实很痛苦，意义也不大。 对照着Probabilistic Topic Models直接看LdaGibbsSampling.java的源码 基本上这样一圈下来，基本概念和算法实现都应该搞定了，当然，数学证明其实没那么容易就搞定，但是对于工程师来说，先把这些搞定就能干活了，这个步骤并不适合各位读博士发论文的同学们，但是这样先看看也比较容易对于这些数学问题的兴趣，不然，成天对这符号和数学公式，没有整块业余时间的我是觉得还是容易退缩放弃的。 发现作为工程师来说，还是看代码比较有感觉，看实际应用的实例比较有感觉，看来不能把大部分时间花在PRML上，还是要多对照着代码看。]]></description>
			<content:encoded><![CDATA[<p>这一阵为了工作上的关系，花了点时间学习了一下<a href="http://en.wikipedia.org/wiki/Latent_Dirichlet_allocation">LDA</a>算法，说实话，对于我这个学CS而非学数学的人来说，除了<a href="http://book.douban.com/subject/3288908/">集体智慧编程</a>这本书之外基本没怎么看过机器学习的人来说，一开始还真是摸不太到门道，前前后后快要四个月了，算是基本了解了这个算法的实现，记录一下，也供后来人快速入门做个参考。</p>
<p>一开始直接就下了<a href="http://scholar.google.com/scholar?q=LATENT+DIRICHLET+ALLOCATION&#038;hl=en&#038;btnG=Search&#038;as_sdt=1%2C33&#038;as_sdtp=on">Blei的原始的那篇论文</a>来看，但是看了个开头就被Dirichlet分布和几个数学公式打倒，然后因为专心在写项目中的具体的代码，也就先放下了。但是因为发现完全忘记了本科学的概率和统计的内容，只好回头去看大学时候概率论的教材，发现早不知道借给谁了，于是上网买了本，花了几天时间大致回顾了一遍概率论的知识，什么贝叶斯全概率公式，正态分布，二项分布之类的。<br />
后来晚上没事儿的时候，去水木的AI版转了转，了解到了Machine Learning的圣经<a href="http://book.douban.com/subject/2061116/">PRML</a>，考虑到反正也是要长期学习了，搞了电子版，同时上淘宝买了个打印胶装的版本。春节里每天晚上看一点儿，扫了一下前两章，再次回顾了一下基本数学知识，然后了解了下贝叶斯学派那种采用共轭先验来建模的方式。于是再次尝试回头去看Blei的那篇论文，发现还是看不太懂，于是又放下了。然后某天Tony让我准备准备给复旦的同学们share一下我们项目中LDA的使用，为了不露怯，又去翻论文，正好看到Science上这篇<a href="http://www.google.com/url?sa=t&#038;source=web&#038;cd=1&#038;ved=0CB8QFjAA&#038;url=http%3A%2F%2Fwww.umsl.edu%2F~sauterv%2FDSS4BI%2Flinks%2Fp16-anthes.pdf&#038;ei=O4GFTYCfII6osAOsibn7AQ&#038;usg=AFQjCNHHBMGPYHrA6PYi1TxM8BGcJyTnQA">Topic Models Vs. Unstructured Data</a>的科普性质的文章，翻了一遍之后，再去PRML里看了一遍Graphic Models那一张，觉得对于LDA想解决的问题和方法了解了更清楚了。之后从search engine里搜到这篇<a href="http://www.52nlp.cn/tears-and-uninitiated-learn-from-natural-language-processing-heros">文章</a>，然后根据推荐读了一部分的<a href="http://scholar.google.com/scholar?q=Gibbs+Sampling+for+the+Uninitiated&#038;hl=en&#038;as_sdt=0&#038;as_vis=1&#038;oi=scholart">Gibbs Sampling for the Uninitiated</a>。之后忘了怎么又搜到了Mark Steyvers和Tom Griffiths合著的<a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.80.9625&#038;rep=rep1&#038;type=pdf">Probabilistic Topic Models</a>，在某个周末往返北京的飞机上读完了，觉得基本上模型训练过程也明白了。再之后就是读了一下这个<a href="http://www.google.com/url?sa=t&#038;source=web&#038;cd=3&#038;ved=0CCUQFjAC&#038;url=http%3A%2F%2Fwww.arbylon.net%2Fprojects%2FLdaGibbsSampler.java&#038;ei=9YGFTa2YI5CksQPx142GAg&#038;usg=AFQjCNE-aJ83icrLWIe0bBeFyDHo6Srfuw">最简版的LDA Gibbs Sampling</a>的实现，再回过头读了一下<a href="http://code.google.com/p/plda/">PLDA</a>的源码，基本上算是对LDA有了个相对清楚的了解。</p>
<p>这样前前后后，也过去了三个月，其实不少时间都是浪费掉的，比如Blei的论文在没有任何相关知识的情况下一开始读了好几次，都没读完而且得到到信息也很有限，如果重新总结一下，我觉得对于我们这些门外汉程序员来说，想了解LDA大概需要这些知识:</p>
<ul>
<li>有基本的概率论的知识，这个拿个大学的课本大概翻一下就好了</li>
<li>PRML的前两章和Graphic Model那部分需要浏览一下，了解一下所谓的贝叶斯学派的方法论，然后理解共轭先验的概念，以及Graphic Model的图形表达的意思。</li>
<li>了解一下Gibbs Sampling的概念</li>
<li>直接读Steyvers的Probabilistic Topic Models，没必要一定去读Blei的论文，开创性的论文不一定好读，最典型的例子就是Paxos了，30多页里多少都是希腊人名，对于英文不够精通，学术训练比较少的工程师来说，其实很痛苦，意义也不大。</li>
<li>对照着Probabilistic Topic Models直接看LdaGibbsSampling.java的源码</li>
</ul>
<p>基本上这样一圈下来，基本概念和算法实现都应该搞定了，当然，数学证明其实没那么容易就搞定，但是对于工程师来说，先把这些搞定就能干活了，这个步骤并不适合各位读博士发论文的同学们，但是这样先看看也比较容易对于这些数学问题的兴趣，不然，成天对这符号和数学公式，没有整块业余时间的我是觉得还是容易退缩放弃的。</p>
<p>发现作为工程师来说，还是看代码比较有感觉，看实际应用的实例比较有感觉，看来不能把大部分时间花在PRML上，还是要多对照着代码看。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2011/03/20/suggestions-for-programmers-to-learn-lda/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>作为一个程序员，数学对你到底有多重要</title>
		<link>http://www.xuwenhao.com/2011/02/01/how-import-is-math-for-a-programmer/</link>
		<comments>http://www.xuwenhao.com/2011/02/01/how-import-is-math-for-a-programmer/#comments</comments>
		<pubDate>Tue, 01 Feb 2011 14:58:08 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Math]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=768</guid>
		<description><![CDATA[每个计算机系毕业的人，大都学过不少数学课，而且不少学校的计算机系的数学课，通常比一般的其他工科专业的数学要难一些，比如不上高等数学，而是学数学分析，不上线性代数而去上高等代数。但是，大部分毕业了后去做程序员的人，即使是所谓的名校计算机系毕业的，大都工作中也基本完全用不上学的那些数学，基本上，一半时间在CRUD，另一半时间在处理各类字符串、链表、Hash表，知道在面试中回答各种排序的时间复杂度是他们需要的数学的上线了。 而在念书的时候，虽然上大学之前，有不少内行的外行的，年老的年轻的人告诉你，数学很重要啊。但是，通常来说，各个学校的计算机系的同学么，爱好学习的，可能重视的也是Thinking in Java，C++ Primer之类的语言书，或者设计模式之类的架构书，抑或是算法与数据结构这些玩意儿；而像我这样天天偷懒放羊的，也不会把数学当作是什么重要的课程好好学习。所以，“数学真重要”，这句话，似乎对于大家来说，始终只是飘在天上的一句话，随风飘逝了。 于是，五年过去了，程序员们都有了不少的工作经验了，如果不是对工作毫无追求混吃等死的程序员的话，对于天天干活的语言，不论是Java还是C++应该都熟能生巧了，所谓的设计模式、重构、自动化测试等等也手到擒来了，大部分人的title上都加上了Senior了，牛一点的后面大概还跟上了一个Manager，然而，大家都开始考虑一个新的问题——“30岁以后怎么半？”，于是，转PM的转PM，考公务员的考公务员，像我这样仍然抱定——“你看人家美国Rohit都50了还不是天天写程序，别人想请还请不到的”的单纯想法的人越来越少了。然后，就算这些人，时不时也会觉得，自己天天干的超越CRUD的，所谓写点OO的框架，不也是很无聊的体力活么，写程序的人干两年谁都会干。于是，又有不少人下海创业了，多年以后，这些人中的大部分都会和我一样悲催的没有挣到前继续回来给大大小小的公司写程序。 其实，杯具往往发生在一开始，其实，要是咱们当年好好学习，才会发现，也许数学对于你当个不错的程序员来说，没那么重要，但是要再往上走一步，有一点点技术上的创新，就都是数学的事儿了。两年前，我在T公司，用Configurator处理某个程序的时候，开始有点儿意识到这一点了，于是，那阵子还花了不少时间重新翻了翻数理逻辑。今年，换了新工作后为了工作看点儿机器学习的东西的时候，终于发现，这全都是数学啊。当你要超越CRUD，做任何一点点有创新性的技术的时候（不说产品），最有机会遇到的问题，其实是数学问题。虽然从Spring到Hibernate到Rails之类的框架，或者Hadoop，HBase之类的分布式计算框架，也都是技术上的重大革新，但是这些框架类的程序，完善都是阶段性的，一旦出现后，很快都会有相应的Best Practice，又会成为熟练工种的活。而真正针对问题域的解答，反是每天都可以有些新鲜的想法、思路和方案的，这些，往往有个数学的门槛。所以如果你真是挺喜欢写程序的，而且希望自己一直能写更好玩更难的程序，总有一天，你要过了这一道坎儿。 所以我很是同意不知道是谁说得，如果你只想当个good programmer，那么数学不重要。但是如果你想当个great programmer，那么数学很重要。在你手里只有锤子的时候，你看什么东西都会是个钉子，想想你如果没有学过算法和数据结构，可能你的大部分程序需要自己写排序的话，都会是傻傻地冒泡吧，反正对于大部分程序来说，在现在这么快的PC下，这点时间差别，大部分情况下，也就是让你等程序执行测试的时候，多个倒杯水的时间。但是很多新鲜，好玩，有挑战的问题，很多数学的概念没有的话，恐怕不是多等个倒水的时间了。而如果你过了这个门槛，你又会发现，一个崭新的世界，又到了你的面前。 回过头来，我说数学重要的话，那么重要的是哪些呢？大家常说的通常是离散数学，不过最近比较热门的机器学习这个方向，我目前看到的相关资料都大量依赖于线性代数和概率论，以及一点点微积分。所以，如果你和我一样，希望做点有追求的技术工作的话，开始花点时间学习数学吧。其实万事开头难，也许你和我一样，对着一堆公式符号，感到头晕眼花，但是如果真得按下心来，看上一个小时，这么坚持个一周，其实就会发现，这没啥难的，就当学门新的编程语言得了。 PS：如果在google中搜索程序员 数学的话，第一个链接是程序员怎样学数学，我觉得这篇文章写得相当不错。我也非常同意，广度有限比较有效，容易激发学习的兴趣，而且能和实际的工作和现实世界的问题、项目相结合。]]></description>
			<content:encoded><![CDATA[<p>每个计算机系毕业的人，大都学过不少数学课，而且不少学校的计算机系的数学课，通常比一般的其他工科专业的数学要难一些，比如不上高等数学，而是学数学分析，不上线性代数而去上高等代数。但是，大部分毕业了后去做程序员的人，即使是所谓的名校计算机系毕业的，大都工作中也基本完全用不上学的那些数学，基本上，一半时间在CRUD，另一半时间在处理各类字符串、链表、Hash表，知道在面试中回答各种排序的时间复杂度是他们需要的数学的上线了。</p>
<p>而在念书的时候，虽然上大学之前，有不少内行的外行的，年老的年轻的人告诉你，数学很重要啊。但是，通常来说，各个学校的计算机系的同学么，爱好学习的，可能重视的也是Thinking in Java，C++ Primer之类的语言书，或者设计模式之类的架构书，抑或是算法与数据结构这些玩意儿；而像我这样天天偷懒放羊的，也不会把数学当作是什么重要的课程好好学习。所以，“数学真重要”，这句话，似乎对于大家来说，始终只是飘在天上的一句话，随风飘逝了。</p>
<p>于是，五年过去了，程序员们都有了不少的工作经验了，如果不是对工作毫无追求混吃等死的程序员的话，对于天天干活的语言，不论是Java还是C++应该都熟能生巧了，所谓的设计模式、重构、自动化测试等等也手到擒来了，大部分人的title上都加上了Senior了，牛一点的后面大概还跟上了一个Manager，然而，大家都开始考虑一个新的问题——“30岁以后怎么半？”，于是，转PM的转PM，考公务员的考公务员，像我这样仍然抱定——“你看人家美国Rohit都50了还不是天天写程序，别人想请还请不到的”的单纯想法的人越来越少了。然后，就算这些人，时不时也会觉得，自己天天干的超越CRUD的，所谓写点OO的框架，不也是很无聊的体力活么，写程序的人干两年谁都会干。于是，又有不少人下海创业了，多年以后，这些人中的大部分都会和我一样悲催的没有挣到前继续回来给大大小小的公司写程序。</p>
<p>其实，杯具往往发生在一开始，其实，要是咱们当年好好学习，才会发现，也许数学对于你当个不错的程序员来说，没那么重要，但是要再往上走一步，有一点点技术上的创新，就都是数学的事儿了。两年前，我在T公司，用Configurator处理某个程序的时候，开始有点儿意识到这一点了，于是，那阵子还花了不少时间重新翻了翻数理逻辑。今年，换了新工作后为了工作看点儿机器学习的东西的时候，终于发现，这全都是数学啊。当你要超越CRUD，做任何一点点有创新性的技术的时候（不说产品），最有机会遇到的问题，其实是数学问题。虽然从Spring到Hibernate到Rails之类的框架，或者Hadoop，HBase之类的分布式计算框架，也都是技术上的重大革新，但是这些框架类的程序，完善都是阶段性的，一旦出现后，很快都会有相应的Best Practice，又会成为熟练工种的活。而真正针对问题域的解答，反是每天都可以有些新鲜的想法、思路和方案的，这些，往往有个数学的门槛。所以如果你真是挺喜欢写程序的，而且希望自己一直能写更好玩更难的程序，总有一天，你要过了这一道坎儿。</p>
<p>所以我很是同意不知道是谁说得，如果你只想当个good programmer，那么数学不重要。但是如果你想当个great programmer，那么数学很重要。在你手里只有锤子的时候，你看什么东西都会是个钉子，想想你如果没有学过算法和数据结构，可能你的大部分程序需要自己写排序的话，都会是傻傻地冒泡吧，反正对于大部分程序来说，在现在这么快的PC下，这点时间差别，大部分情况下，也就是让你等程序执行测试的时候，多个倒杯水的时间。但是很多新鲜，好玩，有挑战的问题，很多数学的概念没有的话，恐怕不是多等个倒水的时间了。而如果你过了这个门槛，你又会发现，一个崭新的世界，又到了你的面前。</p>
<p>回过头来，我说数学重要的话，那么重要的是哪些呢？大家常说的通常是离散数学，不过最近比较热门的机器学习这个方向，我目前看到的相关资料都大量依赖于线性代数和概率论，以及一点点微积分。所以，如果你和我一样，希望做点有追求的技术工作的话，开始花点时间学习数学吧。其实万事开头难，也许你和我一样，对着一堆公式符号，感到头晕眼花，但是如果真得按下心来，看上一个小时，这么坚持个一周，其实就会发现，这没啥难的，就当学门新的编程语言得了。</p>
<p>PS：如果在google中搜索<a href="http://www.google.com/#sclient=psy&#038;hl=en&#038;site=&#038;source=hp&#038;q=程序员+数学&#038;aq=f&#038;aqi=&#038;aql=&#038;oq=&#038;pbx=1&#038;fp=4565d1ad08660d4d">程序员 数学</a>的话，第一个链接是<a href="http://article.yeeyan.org/view/pluto/2365">程序员怎样学数学</a>，我觉得这篇文章写得相当不错。我也非常同意，广度有限比较有效，容易激发学习的兴趣，而且能和实际的工作和现实世界的问题、项目相结合。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2011/02/01/how-import-is-math-for-a-programmer/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>我的IT环境</title>
		<link>http://www.xuwenhao.com/2009/02/21/my-it-stuff/</link>
		<comments>http://www.xuwenhao.com/2009/02/21/my-it-stuff/#comments</comments>
		<pubDate>Sat, 21 Feb 2009 12:24:54 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=719</guid>
		<description><![CDATA[科技越来越发达，工具越来越多，每天的生活都要和你的电脑、软件还有互联网服务打交道。这篇，就来说说我现在常用的软硬件工具和服务： 笔记本一之N610c：毕业没几个月买了台二手的N610c，然后抛弃了原来的拼装台式机。可惜我买二手的东西寿命都不长，现在这台机器通常作为我的第二显示器在写东西需要参考的时候开着，干活是已然不行了，因为南桥主板芯片出了问题，USB口不工作了，电池也充不进电了。 这台机器系统是XP，基本只装了Firefox和Adobe Reader，因为主要用来看看东西啦。 笔记本二之Macbook 466：去年底离职之后把工作电脑上交了，然后立马去买了台新的铝壳麦书，很好用啊很好用，虽然从价格上来说不便宜，摄像头蓝牙都有，多点触控很方便，用惯了改用windows有时候还真有点不习惯…… 这台现在是日常工作机了，每天开机自启动的是Skype和Adium，Adium的好处是可以整合多个IM，不用再MSN+ICQ+QQ+Gtalk开四个IM浪费内存了，而且Adium可以让你整合多个IM的分组，同时将不同IM上的同一人的多个帐号合并在一起，非常方便，不用再一个个IM看某人是否在线了。然后浏览器日常用的是Firefox，当然也装了Safari和Opera测试的时候用用，Firefox里的插件装得不多，发现其实天天要用的也就那么一点，目前只有Adblock Plus，Firebug，Google Gears，Google Toolbar，GreaseMonkey，Remember the Milk for Gmail，Web Developer，wmlbrowser和Zotero。写代码目前主要在玩Ruby和Rails，所以找了个Textmate用用，一直在考虑要不要花钱买下license，当然Eclipse和Netbeans也都装了，自带的Xcode也在，不过Netbeans和Xcode基本没用过；装了Subversion和Git作为SCM的客户端，当然，慢慢习惯用Git之后我觉得SVN可以抛弃了。日常的照片音乐都交给了自带的iLife，看PDF也是用的Preview，反正对我来说已经足够好了。看片用Mplayer 1.0，下载各大盗版则是Amule+Transmission。常常会用到自带的Stickies来记录点东西，自带的Dictionary也很好用，虽然装了QuickSilver，但是我还是更习惯Spotlight，不过貌似这玩意儿有越用越慢的趋势。当然，为了上网上银行，还是搞了个VMWare的Windows虚拟机的。 手机一之Nokia 6630：也是毕业没多久买的，到现在还正常工作。手机有强烈的诺基亚风格，就是难看，但是皮实经摔好用，电话短信不会有问题，也不会死机重启之类，电池也能撑三四天。买的时候也算是当时的牛机了，现在看上去则是连山寨也不如了。刚买那会儿装了不少软件折腾，还拿这个看电影听MP3啥的，现在上面只有三个非自带的软件，分别是A4输入法，MSN和UCWeb。意欲装Frings在手机上控制所有IM可惜它不卖面子始终没法用，而UCWeb则是战胜了Opera Mini占据了手机上的位置，常常用它在老婆逛街的时候看看Google Readers里订阅的内容。还值得一提的是，这台机器通过Google Sync可以把Gmail里的Contacts和手机上的双向同步，方便了备份和转移电话本了。 手机二之Blackberry 8310：去年买的号称全新机，看到号称这两个字你就知道是翻新机了，在不长的时间里已经出了两次问题，这不前两天又拿到JS那里去修了，每次买二手的东西，我的RP都很差，所以下定决心以后不碰二手的东西了。虽然常常不能好好用，但是不可否认Blackberry是设计优良的机器，虽然用不上push mail费了一半，但是这台机器通过Google Sync可以同步联系人之外，还能同步Calendar，然后买了Remember the Milk的Pro服务还能同步Todo list，就可以完全把PIM的功能随身携带。另外，上面的Gmail的客户端也很不错，因为是全键盘，通过快捷键操作还是非常方便的。还有个好处是开软件不像其他机器那么费电，机器的按键和滚轮手感也不错，现在我就希望这台机器这回修好别再出问题了。 MP3之iPod shuffle 2：一台银色的夹子shuffle，不该买的，话说这其实也是台二手的，新蛋上买的，不过用的实在不多，浪费了，话说二手真是我的诅咒啊。 互联网服务：Mail自然毫无疑问是Gmail。然后是一系列的Google服务，因为Google Reader的分享功能用它替代了Bloglines；用Google Docs做读书笔记或者整理各种零散的笔记；用Google Calendar做日程表，虽然最近没什么计划性。然后Todo list因为Google自带的实在是不太好用，所以用的是Remember the Milk，装了Firefox的插件所以可以和Gmail很好地整合。Blog是host在Dreamhost上的，然后代码则是用Github取代了不稳定的Google Code。 看了看，发现自己用的东西还是很简单的，同学们也来分享一下自己用的软硬件和服务吧。]]></description>
			<content:encoded><![CDATA[<p>科技越来越发达，工具越来越多，每天的生活都要和你的电脑、软件还有互联网服务打交道。这篇，就来说说我现在常用的软硬件工具和服务：</p>
<p>笔记本一之N610c：毕业没几个月买了台二手的N610c，然后抛弃了原来的拼装台式机。可惜我买二手的东西寿命都不长，现在这台机器通常作为我的第二显示器在写东西需要参考的时候开着，干活是已然不行了，因为南桥主板芯片出了问题，USB口不工作了，电池也充不进电了。<br />
这台机器系统是XP，基本只装了Firefox和Adobe Reader，因为主要用来看看东西啦。</p>
<p>笔记本二之Macbook 466：去年底离职之后把工作电脑上交了，然后立马去买了台新的铝壳麦书，很好用啊很好用，虽然从价格上来说不便宜，摄像头蓝牙都有，多点触控很方便，用惯了改用windows有时候还真有点不习惯……<br />
这台现在是日常工作机了，每天开机自启动的是Skype和<a href="http://www.adiumx.com" target="_blank">Adium</a>，Adium的好处是可以整合多个IM，不用再MSN+ICQ+QQ+Gtalk开四个IM浪费内存了，而且Adium可以让你整合多个IM的分组，同时将不同IM上的同一人的多个帐号合并在一起，非常方便，不用再一个个IM看某人是否在线了。然后浏览器日常用的是Firefox，当然也装了Safari和Opera测试的时候用用，Firefox里的插件装得不多，发现其实天天要用的也就那么一点，目前只有Adblock Plus，Firebug，Google Gears，Google Toolbar，GreaseMonkey，Remember the Milk for Gmail，Web Developer，wmlbrowser和Zotero。写代码目前主要在玩Ruby和Rails，所以找了个Textmate用用，一直在考虑要不要花钱买下license，当然Eclipse和Netbeans也都装了，自带的Xcode也在，不过Netbeans和Xcode基本没用过；装了Subversion和Git作为SCM的客户端，当然，慢慢习惯用Git之后我觉得SVN可以抛弃了。日常的照片音乐都交给了自带的iLife，看PDF也是用的Preview，反正对我来说已经足够好了。看片用Mplayer 1.0，下载各大盗版则是Amule+Transmission。常常会用到自带的Stickies来记录点东西，自带的Dictionary也很好用，虽然装了QuickSilver，但是我还是更习惯Spotlight，不过貌似这玩意儿有越用越慢的趋势。当然，为了上网上银行，还是搞了个VMWare的Windows虚拟机的。</p>
<p>手机一之Nokia 6630：也是毕业没多久买的，到现在还正常工作。手机有强烈的诺基亚风格，就是难看，但是皮实经摔好用，电话短信不会有问题，也不会死机重启之类，电池也能撑三四天。买的时候也算是当时的牛机了，现在看上去则是连山寨也不如了。刚买那会儿装了不少软件折腾，还拿这个看电影听MP3啥的，现在上面只有三个非自带的软件，分别是A4输入法，MSN和UCWeb。意欲装Frings在手机上控制所有IM可惜它不卖面子始终没法用，而UCWeb则是战胜了Opera Mini占据了手机上的位置，常常用它在老婆逛街的时候看看Google Readers里订阅的内容。还值得一提的是，这台机器通过Google Sync可以把Gmail里的Contacts和手机上的双向同步，方便了备份和转移电话本了。</p>
<p>手机二之Blackberry 8310：去年买的号称全新机，看到号称这两个字你就知道是翻新机了，在不长的时间里已经出了两次问题，这不前两天又拿到JS那里去修了，每次买二手的东西，我的RP都很差，所以下定决心以后不碰二手的东西了。虽然常常不能好好用，但是不可否认Blackberry是设计优良的机器，虽然用不上push mail费了一半，但是这台机器通过Google Sync可以同步联系人之外，还能同步Calendar，然后买了Remember the Milk的Pro服务还能同步Todo list，就可以完全把PIM的功能随身携带。另外，上面的Gmail的客户端也很不错，因为是全键盘，通过快捷键操作还是非常方便的。还有个好处是开软件不像其他机器那么费电，机器的按键和滚轮手感也不错，现在我就希望这台机器这回修好别再出问题了。</p>
<p>MP3之iPod shuffle 2：一台银色的夹子shuffle，不该买的，话说这其实也是台二手的，新蛋上买的，不过用的实在不多，浪费了，话说二手真是我的诅咒啊。</p>
<p>互联网服务：Mail自然毫无疑问是<a href="http://mail.google.com" target="_blank">Gmail</a>。然后是一系列的Google服务，因为<a href="http://reader.google.com" target="_blank">Google Reader</a>的分享功能用它替代了<a href="http://www.bloglines.com" target="_blank">Bloglines</a>；用<a href="http://docs.google.com" target="_blank">Google Docs</a>做读书笔记或者整理各种零散的笔记；用<a href="http://calendar.google.com" target="_blank">Google Calendar</a>做日程表，虽然最近没什么计划性。然后Todo list因为Google自带的实在是不太好用，所以用的是<a href="http://www.rememberthemilk.com" target="_blank">Remember the Milk</a>，装了Firefox的插件所以可以和Gmail很好地整合。Blog是host在<a href="http://www.dreamhost.com" target="_blank">Dreamhost</a>上的，然后代码则是用<a href="http://www.github.com" target="_blank">Github</a>取代了不稳定的<a href="http://code.google.com">Google Code</a>。</p>
<p>看了看，发现自己用的东西还是很简单的，同学们也来分享一下自己用的软硬件和服务吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2009/02/21/my-it-stuff/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>在新macbook上安装Rails+MySQL</title>
		<link>http://www.xuwenhao.com/2009/02/09/install-rails-with-mysql-on-new-macboo/</link>
		<comments>http://www.xuwenhao.com/2009/02/09/install-rails-with-mysql-on-new-macboo/#comments</comments>
		<pubDate>Mon, 09 Feb 2009 14:37:33 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Mac]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[Rails]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=672</guid>
		<description><![CDATA[嗯，嗯，嗯，这个问题前一阵来来回回折腾过不少时间，主要的问题在于 Macbook 466是64位的CPU Leopard自带的Ruby是32位的版本 如果安装的MySQL是64位版本的，就需要自己编译个Ruby 要不你就像我这样还是装个32位的MySQL吧 MySQL安装的注意事项 建议安装Startup Item，这样就开机自启动了 如果装了Startup Item但是不想开机自启动，那就修改/etc/hostconfig，把MYSQLCOM=-YES-改成MYSQLCOM=-NO- 默认的encoding是latin1，所以要改一下配置文件，按下面这么办就行了 $ sudo cp /usr/local/mysql/support-files/my-small.cnf /etc/my.cnf $ sudo vim /etc/my.cnf # 在对应的节点添加如下信息 [client] default-character-set = utf8 [mysqld] character-set-server = utf8 default-table-type = innodb 记得数据库创建要在改完配置重启mysqld之后，不然创建的数据库默认还是latin1的 然后就是gem安装mysql的驱动了，抛弃掉Rails自带的过时的ruby版本的驱动了 sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config 如果您装的是64位的Ruby和MySQL那么改一个参数吧 sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config]]></description>
			<content:encoded><![CDATA[<p>嗯，嗯，嗯，这个问题前一阵来来回回折腾过不少时间，主要的问题在于</p>
<ul>
<li>Macbook 466是64位的CPU</li>
<li>Leopard自带的Ruby是32位的版本</li>
<li>如果安装的MySQL是64位版本的，就需要自己编译个Ruby</li>
<li>要不你就像我这样还是装个32位的MySQL吧</li>
</ul>
<p>MySQL安装的注意事项</p>
<ul>
<li>建议安装Startup Item，这样就开机自启动了</li>
<li>如果装了Startup Item但是不想开机自启动，那就修改/etc/hostconfig，把MYSQLCOM=-YES-改成MYSQLCOM=-NO-</li>
<li>默认的encoding是latin1，所以要改一下配置文件，按下面这么办就行了</li>
</ul>
<pre name="code" class="ruby">
   $ sudo cp /usr/local/mysql/support-files/my-small.cnf /etc/my.cnf
   $ sudo vim /etc/my.cnf
   # 在对应的节点添加如下信息
   [client]
   default-character-set = utf8
   [mysqld]
   character-set-server = utf8
   default-table-type = innodb </pre>
<p>记得数据库创建要在改完配置重启mysqld之后，不然创建的数据库默认还是latin1的</p>
<p>然后就是gem安装mysql的驱动了，抛弃掉Rails自带的过时的ruby版本的驱动了</p>
<pre name="code" class="ruby">
sudo env ARCHFLAGS="-arch i386" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
</pre>
<p>如果您装的是64位的Ruby和MySQL那么改一个参数吧</p>
<pre name="code" class="ruby">
sudo env ARCHFLAGS="-arch x86_64" gem install mysql -- --with-mysql-config=/usr/local/mysql/bin/mysql_config
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2009/02/09/install-rails-with-mysql-on-new-macboo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>折腾了一下午</title>
		<link>http://www.xuwenhao.com/2008/11/17/fighting-with-bugs-whole-afternoo/</link>
		<comments>http://www.xuwenhao.com/2008/11/17/fighting-with-bugs-whole-afternoo/#comments</comments>
		<pubDate>Mon, 17 Nov 2008 07:43:43 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=610</guid>
		<description><![CDATA[遇上了n个bug，本来是想下个FM2009的Mac版，结果transmission罢工，一开始以为是种子过期了，可是换了一个还是一样的毛病，始终报Tracker request failed。研究了一下，发现是一个1.40版的已知bug，于是只好去下了个nightly build的版本，结果……没罢工但是完全没速度啊。 接下来是准备开工写个rails的app，看了一眼官方站点，貌似Leopard是自带ruby，rails，gem等等等，结果又是一堆错，好在这个提示还比较明确，告诉我rake版本太低，于是sudo gem update。然后又是一堆错，看了一眼，发现又是一个bug，可耻的是，居然还没fix，更可耻的是，居然这个bug已经发现有一年了……提供的work around方案就是删了重装而不要update，边考虑边顺手update了过时的rubygem版本。出问题的都是update好的lib后generate的doc，本来想忍了，想想还是继续折腾吧，搞彻底了以防以后再出sb的问题。所以谁也在Leopard下用ror，如果发现update的时候console出现下面这样的出错提示： ERROR:  While generating documentation for net-sftp-2.0.1 &#8230; MESSAGE:   Unhandled special: Special: type=33, text=&#8221;Net::SFTP&#8221; &#8230; RDOC args: &#8211;ri &#8211;op /Library/Ruby/Gems/1.8/doc/net-sftp-2.0.1/ri &#8211;line-numbers &#8211;inline-source &#8211;title Net-sftp &#8211;main README.rdoc &#8211;quiet lib CHANGELOG.rdoc lib/net/sftp/constants.rb lib/net/sftp/errors.rb lib/net/sftp/operations/dir.rb lib/net/sftp/operations/download.rb lib/net/sftp/operations/file.rb lib/net/sftp/operations/file_factory.rb lib/net/sftp/operations/upload.rb lib/net/sftp/packet.rb lib/net/sftp/protocol/01/attributes.rb lib/net/sftp/protocol/01/base.rb lib/net/sftp/protocol/01/name.rb lib/net/sftp/protocol/02/base.rb lib/net/sftp/protocol/03/base.rb lib/net/sftp/protocol/04/attributes.rb lib/net/sftp/protocol/04/base.rb lib/net/sftp/protocol/04/name.rb lib/net/sftp/protocol/05/base.rb lib/net/sftp/protocol/06/attributes.rb [...]]]></description>
			<content:encoded><![CDATA[<p>遇上了n个bug，本来是想下个FM2009的Mac版，结果<a href="http://www.transmissionbt.com" target="_blank">transmission</a>罢工，一开始以为是种子过期了，可是换了一个还是一样的毛病，始终报Tracker request failed。研究了一下，发现是一个1.40版的已知<a href="http://trac.transmissionbt.com/ticket/1447" target="_blank">bug</a>，于是只好去下了个nightly build的版本，结果……没罢工但是完全没速度啊。</p>
<p>接下来是准备开工写个rails的app，看了一眼官方站点，貌似Leopard是自带ruby，rails，gem等等等，结果又是一堆错，好在这个提示还比较明确，告诉我rake版本太低，于是sudo gem update。然后又是一堆错，看了一眼，发现又是一个<strong><a href="http://dev.rubyonrails.org/ticket/9796" target="_blank">bug</a></strong>，可耻的是，居然还没fix，更可耻的是，居然这个bug已经发现有一年了……提供的work around方案就是删了重装而不要update，边考虑边顺手update了过时的rubygem版本。出问题的都是update好的lib后generate的doc，本来想忍了，想想还是继续折腾吧，搞彻底了以防以后再出sb的问题。所以谁也在Leopard下用ror，如果发现update的时候console出现下面这样的出错提示：</p>
<p>ERROR:  While generating documentation for net-sftp-2.0.1</p>
<p>&#8230; MESSAGE:   Unhandled special: Special: type=33, text=&#8221;Net::SFTP&#8221;</p>
<p>&#8230; RDOC args: &#8211;ri &#8211;op /Library/Ruby/Gems/1.8/doc/net-sftp-2.0.1/ri &#8211;line-numbers &#8211;inline-source &#8211;title Net-sftp &#8211;main README.rdoc &#8211;quiet lib CHANGELOG.rdoc lib/net/sftp/constants.rb lib/net/sftp/errors.rb lib/net/sftp/operations/dir.rb lib/net/sftp/operations/download.rb lib/net/sftp/operations/file.rb lib/net/sftp/operations/file_factory.rb lib/net/sftp/operations/upload.rb lib/net/sftp/packet.rb lib/net/sftp/protocol/01/attributes.rb lib/net/sftp/protocol/01/base.rb lib/net/sftp/protocol/01/name.rb lib/net/sftp/protocol/02/base.rb lib/net/sftp/protocol/03/base.rb lib/net/sftp/protocol/04/attributes.rb lib/net/sftp/protocol/04/base.rb lib/net/sftp/protocol/04/name.rb lib/net/sftp/protocol/05/base.rb lib/net/sftp/protocol/06/attributes.rb lib/net/sftp/protocol/06/base.rb lib/net/sftp/protocol/base.rb lib/net/sftp/protocol.rb lib/net/sftp/request.rb lib/net/sftp/response.rb lib/net/sftp/session.rb lib/net/sftp/version.rb lib/net/sftp.rb README.rdoc</p>
<p>(continuing with the rest of the installation)</p>
<div>就麻烦你自己把旧版本的rdoc删了重生吧……</div>
<div></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2008/11/17/fighting-with-bugs-whole-afternoo/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Gmail的新Feature</title>
		<link>http://www.xuwenhao.com/2008/11/13/gmail-new-feature/</link>
		<comments>http://www.xuwenhao.com/2008/11/13/gmail-new-feature/#comments</comments>
		<pubDate>Thu, 13 Nov 2008 12:55:13 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[News]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/?p=607</guid>
		<description><![CDATA[不知道是不是过时新闻了，不过今天发现gmail左上角多了个&#8220;New! Video Chat&#8221;的红色链接，原来，史上最强大的Web Mail，现在更加强大了，可以直接通过Gmail页面里使用Google Talk的Video Chat了。好吧好吧，虽然Google App还没有把我希望的PIM完全结合到Gmail中，但是我不得不承认，Google实在是太强大了，事实上，我都不曾想过他们可以把Video Chat集成到网页中，但是……他们居然真得这么做了，好吧好吧，我现在要把他们家当成我得dream company了。 我还没能找到人试验一把他们得Web Video Chat质量怎么样，所以如果有人愿意尝试得话，可以Call我Blog右边得Google Talk帐号。 PS：他们的宣传视频里用的机器也是Mac。]]></description>
			<content:encoded><![CDATA[<div>
<p>不知道是不是过时新闻了，不过今天发现gmail左上角多了个<a href="http://mail.google.com/videochat/" target="_blank">&#8220;New! Video Chat&#8221;</a>的红色链接，原来，史上最强大的Web Mail，现在更加强大了，可以直接通过Gmail页面里使用Google Talk的Video Chat了。好吧好吧，虽然Google App还没有把我希望的PIM完全结合到Gmail中，但是我不得不承认，Google实在是太强大了，事实上，我都不曾想过他们可以把Video Chat集成到网页中，但是……他们居然真得这么做了，好吧好吧，我现在要把他们家当成我得dream company了。</p>
<p>我还没能找到人试验一把他们得Web Video Chat质量怎么样，所以如果有人愿意尝试得话，可以Call我Blog右边得Google Talk帐号。</p>
<p>PS：他们的宣传视频里用的机器也是Mac。</p></div>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2008/11/13/gmail-new-feature/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>ant版本兼容性的问题</title>
		<link>http://www.xuwenhao.com/2008/01/16/ant-version-issue/</link>
		<comments>http://www.xuwenhao.com/2008/01/16/ant-version-issue/#comments</comments>
		<pubDate>Tue, 15 Jan 2008 16:53:25 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/2008/01/16/ant-version-issue/</guid>
		<description><![CDATA[折腾了大半天，跑ADI的时候，到一半就抛错 unknown argument: -cp-usage ant [options] [target [target2] google了一把，一般都说啥cmd和bat脚本不对啦，删掉/etc/下的config文件啦，最后发现是，ant1.6.3以下版本不支持-cp参数而只有-lib参数。我在copy项目依赖的ant相关的jar的时候，用1.6.2的jar覆盖了1.6.5版本的，导致cmd和bat脚本都是1.6.5的，而实际用的jar是1.6.2的。]]></description>
			<content:encoded><![CDATA[<p>折腾了大半天，跑ADI的时候，到一半就抛错</p>
<blockquote><p>unknown argument: -cp<br />-usage ant [options] [target [target2] </p></blockquote>
<p>google了一把，一般都说啥cmd和bat脚本不对啦，删掉/etc/下的config文件啦，最后发现是，ant1.6.3以下版本不支持-cp参数而只有-lib参数。我在copy项目依赖的ant相关的jar的时候，用1.6.2的jar覆盖了1.6.5版本的，导致cmd和bat脚本都是1.6.5的，而实际用的jar是1.6.2的。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2008/01/16/ant-version-issue/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>相见恨晚的Opera</title>
		<link>http://www.xuwenhao.com/2007/11/26/recommend-opera-browser/</link>
		<comments>http://www.xuwenhao.com/2007/11/26/recommend-opera-browser/#comments</comments>
		<pubDate>Mon, 26 Nov 2007 12:22:54 +0000</pubDate>
		<dc:creator>xuwenhao</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/201</guid>
		<description><![CDATA[闻名不如见面啊。既然连小叮当同学都推荐了Opera放弃了Firefox，昨天晚上便下了9.24下来试了一把。结果就是，我把前两天刚下的FF3.01beta给删了，现在机器上只留了IE6，FF2和Opera9.24了。 简单，快速，UI和Logo很漂亮，有一些很不错的Feature，比如快速拨号，网页缩略图，自带的download manager，Opera Link等等。 虽然插件机制比FF2差了不少，但是可以用User Script，基本上等于有了个GreaseMonkey，所以可定制性还是不错的。FF2的插件机制虽然好，但是一来浏览器就是浏览器，很多基于XAML的功能其实我根本不会去用，反而习惯于下载单独的软件，就比如Eclipse虽好，但是我机器上的Apatana是个Standalone的版本而不是集成在Eclipse中。二来我不是个Web Developer，毕业以来一直写得是后台的Java code，基本没写过HTML/CSS/JS，所以Firebug等插件对我来说算不上杀手级应用。更何况，FF2以来内存占用越来越大，速度越来越慢，CPU时不时100%。而且这么多年来一直没进步，实在是让人失望啊。 Opera内存占用也不算小（在80-200M之间，没有传说中那么好），不过目前还能忍，不像FF2我开了20个Tab两三天不关机，内存就直上500M了。启动速度快（终于不用像等Eclipse一样等FF启动了），UI和Logo比巨土无比的FF2漂亮（当然，双方都可以换Skin）。然后自带的功能基本够用，不用像FF一样上手一堆插件了，然后“快速拨号”这个新Feature我很喜欢（Ctrl1-9对应预设的九个地址，新标签页默认显示这九个页面的缩略图），适合我这种只去几个固定网站的人。网页缩略图是个很Cool的功能（不过其实没啥用），自带的Downloader Manager，不用像FF2非得装插件了，Opera Link（同步浏览器设置）对于不停在不同机器切换的人很有用，对于我现在一台Laptop到处跑用处不大所以还没仔细研究。 当然，也有些缺点，一是插件不如FF2丰富，对于Web Developer来说FF还是不可或缺啊。二是页面如果连不上没有地方看当前浏览器在啥（或许是我没找到），不像FF可以马上知道是被盾还是DNS解析问题。三就是网页兼容性了，不过目前我常去的地方都没啥问题，但是应该比FF还要差一些吧。 网上看了一下Opera的历史，发现又是一家很有趣很有创新精神的公司啊：创新的Opera 1994年，Opera 发明了多标签浏览方式 1994年，Opera 首创页面缩放 1996年，Opera 首创会话功能 2000年，Opera 成为第一个可以拦截弹出窗口的浏览器 2000年，Opera 第一个在浏览器的工具栏上集成搜索框 2000年，Opera 第一个在浏览器中集成了删除隐私数据的功能 2000年，Opera 发明鼠标手势 2005年，Opera 开始支持用户自定义Javascript脚本 2005年，Opera 第一个在浏览器中集成BT下载功能 2006年，Opera 第一个在浏览器中集成widgets 2007年，Opera 首创快速拨号]]></description>
			<content:encoded><![CDATA[<p>闻名不如见面啊。既然连小叮当同学都推荐了<a HREF="http://cn.opera.com">Opera</a>放弃了<a HREF="http://www.getfirefox.com">Firefox</a>，昨天晚上便下了9.24下来试了一把。结果就是，我把前两天刚下的FF3.01beta给删了，现在机器上只留了IE6，FF2和Opera9.24了。</p>
<p>简单，快速，UI和Logo很漂亮，有一些很不错的Feature，比如快速拨号，网页缩略图，自带的download manager，Opera Link等等。</p>
<p>虽然插件机制比FF2差了不少，但是可以用User Script，基本上等于有了个GreaseMonkey，所以可定制性还是不错的。FF2的插件机制虽然好，但是一来浏览器就是浏览器，很多基于XAML的功能其实我根本不会去用，反而习惯于下载单独的软件，就比如Eclipse虽好，但是我机器上的Apatana是个Standalone的版本而不是集成在Eclipse中。二来我不是个Web Developer，毕业以来一直写得是后台的Java code，基本没写过HTML/CSS/JS，所以Firebug等插件对我来说算不上杀手级应用。更何况，FF2以来内存占用越来越大，速度越来越慢，CPU时不时100%。而且这么多年来一直没进步，实在是让人失望啊。</p>
<p>Opera内存占用也不算小（在80-200M之间，没有传说中那么好），不过目前还能忍，不像FF2我开了20个Tab两三天不关机，内存就直上500M了。启动速度快（终于不用像等Eclipse一样等FF启动了），UI和Logo比巨土无比的FF2漂亮（当然，双方都可以换Skin）。然后自带的功能基本够用，不用像FF一样上手一堆插件了，然后“快速拨号”这个新Feature我很喜欢（Ctrl1-9对应预设的九个地址，新标签页默认显示这九个页面的缩略图），适合我这种只去几个固定网站的人。网页缩略图是个很Cool的功能（不过其实没啥用），自带的Downloader Manager，不用像FF2非得装插件了，Opera Link（同步浏览器设置）对于不停在不同机器切换的人很有用，对于我现在一台Laptop到处跑用处不大所以还没仔细研究。</p>
<p>当然，也有些缺点，一是插件不如FF2丰富，对于Web Developer来说FF还是不可或缺啊。二是页面如果连不上没有地方看当前浏览器在啥（或许是我没找到），不像FF可以马上知道是被盾还是DNS解析问题。三就是网页兼容性了，不过目前我常去的地方都没啥问题，但是应该比FF还要差一些吧。</p>
<p>网上看了一下Opera的历史，发现又是一家很有趣很有创新精神的公司啊：<a HREF="http://vvoody.org/blog/?page_id=25">创新的Opera</a><br />
1994年，Opera 发明了多标签浏览方式<br />
1994年，Opera 首创页面缩放<br />
1996年，Opera 首创会话功能<br />
2000年，Opera 成为第一个可以拦截弹出窗口的浏览器<br />
2000年，Opera 第一个在浏览器的工具栏上集成搜索框<br />
2000年，Opera 第一个在浏览器中集成了删除隐私数据的功能<br />
2000年，Opera 发明鼠标手势<br />
2005年，Opera 开始支持用户自定义Javascript脚本<br />
2005年，Opera 第一个在浏览器中集成BT下载功能<br />
2006年，Opera 第一个在浏览器中集成widgets<br />
2007年，Opera 首创快速拨号</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2007/11/26/recommend-opera-browser/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>POJO的来历</title>
		<link>http://www.xuwenhao.com/2007/03/05/pojo%e7%9a%84%e6%9d%a5%e5%8e%86/</link>
		<comments>http://www.xuwenhao.com/2007/03/05/pojo%e7%9a%84%e6%9d%a5%e5%8e%86/#comments</comments>
		<pubDate>Mon, 05 Mar 2007 04:39:57 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/163</guid>
		<description><![CDATA[POJO的来历 蛮好玩的，看来哪儿都一样，不装一下，就没人甩你。]]></description>
			<content:encoded><![CDATA[<p><a title="POJO的来历" target="_blank" href="http://www.martinfowler.com/bliki/POJO.html">POJO的来历</a></p>
<p>蛮好玩的，看来哪儿都一样，不装一下，就没人甩你。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2007/03/05/pojo%e7%9a%84%e6%9d%a5%e5%8e%86/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>XP随便谈——序言</title>
		<link>http://www.xuwenhao.com/2007/01/19/xp%e9%9a%8f%e4%be%bf%e8%b0%88%e2%80%94%e2%80%94%e5%ba%8f%e8%a8%80/</link>
		<comments>http://www.xuwenhao.com/2007/01/19/xp%e9%9a%8f%e4%be%bf%e8%b0%88%e2%80%94%e2%80%94%e5%ba%8f%e8%a8%80/#comments</comments>
		<pubDate>Thu, 18 Jan 2007 18:52:39 +0000</pubDate>
		<dc:creator>xuwenhao</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/153</guid>
		<description><![CDATA[原来写blog与我是一件很快活的事，然而不知从哪一天开始，就忽然觉得没意思起来，好像便秘一样，想是想得，甚至题目都拟好了，然而，却总是出不来。 现在想来，去年的时候，太急躁了，钻进了自己给自己设好的牛角尖里。回头看来，过去的1年半的工作，是追求速度的一年，一切求快，是一个好的开始，却不是好的过程。好的开始，是因为4年的CS读得太烂，不快一点，大概就要待岗在家了。不是好的过程，是因为所有的东西，都浮在表面上，没有足够的积累，所以最近一段时间，陷入了一个两难的境地。 从泥沼中爬出来，不是件容易的事，我也没有想出什么办法来，于是，只好强迫自己，写一点东西，因为写东西，总是要头脑清楚，心里安静才写得出来的。 写XP，是写XP编程，或许，还会有所扩展，之所以写XP，是因为，除了XP自己有点感觉，其它的，怕还是浅浅的入门者，而对于XP，好歹算是天天有所接触的，尽管，工作的地方不是彻底完全的XP，但是，多少，有个对照，这是其一；除此之外，工作一年看下来，大部分Enterprise的Tech，说难无非是算法数据结构上的基本功，要说架构上，那只能是一年一年慢慢修炼的，说简单，就是在成熟的framework下调调API，倒是XP的方法论和实践，很多时候，产生的效用更大一下。 &#8220;I am not a great programmer, I am just a good programmer with great habbit.&#8221;]]></description>
			<content:encoded><![CDATA[<p>原来写blog与我是一件很快活的事，然而不知从哪一天开始，就忽然觉得没意思起来，好像便秘一样，想是想得，甚至题目都拟好了，然而，却总是出不来。</p>
<p>现在想来，去年的时候，太急躁了，钻进了自己给自己设好的牛角尖里。回头看来，过去的1年半的工作，是追求速度的一年，一切求快，是一个好的开始，却不是好的过程。好的开始，是因为4年的CS读得太烂，不快一点，大概就要待岗在家了。不是好的过程，是因为所有的东西，都浮在表面上，没有足够的积累，所以最近一段时间，陷入了一个两难的境地。</p>
<p>从泥沼中爬出来，不是件容易的事，我也没有想出什么办法来，于是，只好强迫自己，写一点东西，因为写东西，总是要头脑清楚，心里安静才写得出来的。</p>
<p>写XP，是写XP编程，或许，还会有所扩展，之所以写XP，是因为，除了XP自己有点感觉，其它的，怕还是浅浅的入门者，而对于XP，好歹算是天天有所接触的，尽管，工作的地方不是彻底完全的XP，但是，多少，有个对照，这是其一；除此之外，工作一年看下来，大部分Enterprise的Tech，说难无非是算法数据结构上的基本功，要说架构上，那只能是一年一年慢慢修炼的，说简单，就是在成熟的framework下调调API，倒是XP的方法论和实践，很多时候，产生的效用更大一下。</p>
<p>&#8220;I am not a great programmer, I am just a good programmer with great habbit.&#8221;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2007/01/19/xp%e9%9a%8f%e4%be%bf%e8%b0%88%e2%80%94%e2%80%94%e5%ba%8f%e8%a8%80/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>诡异的database问题，记录一下</title>
		<link>http://www.xuwenhao.com/2006/05/25/%e8%af%a1%e5%bc%82%e7%9a%84database%e9%97%ae%e9%a2%98%ef%bc%8c%e8%ae%b0%e5%bd%95%e4%b8%80%e4%b8%8b/</link>
		<comments>http://www.xuwenhao.com/2006/05/25/%e8%af%a1%e5%bc%82%e7%9a%84database%e9%97%ae%e9%a2%98%ef%bc%8c%e8%ae%b0%e5%bd%95%e4%b8%80%e4%b8%8b/#comments</comments>
		<pubDate>Wed, 24 May 2006 16:46:51 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/97</guid>
		<description><![CDATA[Hibernate做O/R Mapping，一个Date类映射到一个timestamp的column，然后save一把，存进去的是一个形如21:00:23.456的timestamp字符串，通过jdbc拿出来，用getString和getTimestamp取，然后用dataformat去parse或者直接toGMTString，发现时区信息，都丢失了。于是考虑直接设置Timezone到GMT，结果发现Hibernate存进去的还是Local Timezone的时间字符串，抓狂，最后发现，用getDate取出timestamp，保留了存进去的时区信息。 真的很奇怪啊。]]></description>
			<content:encoded><![CDATA[<p>Hibernate做O/R Mapping，一个Date类映射到一个timestamp的column，然后save一把，存进去的是一个形如21:00:23.456的timestamp字符串，通过jdbc拿出来，用getString和getTimestamp取，然后用dataformat去parse或者直接toGMTString，发现时区信息，都丢失了。于是考虑直接设置Timezone到GMT，结果发现Hibernate存进去的还是Local Timezone的时间字符串，抓狂，最后发现，用getDate取出timestamp，保留了存进去的时区信息。</p>
<p>真的很奇怪啊。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2006/05/25/%e8%af%a1%e5%bc%82%e7%9a%84database%e9%97%ae%e9%a2%98%ef%bc%8c%e8%ae%b0%e5%bd%95%e4%b8%80%e4%b8%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Podcast初体验</title>
		<link>http://www.xuwenhao.com/2006/05/11/podcast%e5%88%9d%e4%bd%93%e9%aa%8c/</link>
		<comments>http://www.xuwenhao.com/2006/05/11/podcast%e5%88%9d%e4%bd%93%e9%aa%8c/#comments</comments>
		<pubDate>Thu, 11 May 2006 13:44:36 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/86</guid>
		<description><![CDATA[开始订阅和收听Podcast，看了一些blog，感觉Podcast可以成为一种提高时间效率和学习的新的工具，利用Podcast，可以多线程工作，在跑步的时候学习，写Blog时候听新闻。 之前也尝试过收听音乐类的Podcast，不觉得好，一是有广告，造成中断很多，而是我听歌本来就那么几首，所以大部分觉得不好听，于是当时不太看好。 这两天，尝试使用Podcast听一些学习类新闻类的节目，itunes订阅，边上网边听，发现很不错。对Podcast的未来，还是认为内容很重要，或者说，质量很重要，这一点上，Podcast需要的不是所谓Web 2.0那种的用户创建内容，获得高质量的内容，非常非常重要。业余的作者，或许可以写出不错的Blog，浏览者也会很多，生活性的内容也会有朋友来看。但是，Podcast的话，业余一点，我认为能听下去的人很少。没有听众，创作者也会失去兴趣继续制作，于是，产业量就会破坏了。 我的想法是，远程教育，付费内容，可以构成Podcast的产业，Apple Store的模式，可以获得成功。当然，版权始终是一个问题，可能，还是需要内容免费，依靠增值的服务，不过，对于高质量的Podcast，我是愿意付费订阅的。 Itunes用起来很不错，都让我有冲动去买ipod了，不过貌似CPU占用率一上去就会有破声。 Podlook做得很不错，上面能找到不少不错的Podcast。 我订阅了这几个： 锵锵三人行，发现很好玩，听录音的好处在于同时可以干别的事。 ITC: All Programs，IT Conversation的一些录音，适合联系IT类的听力和了解业界前沿的信息，不过我还没仔细听过。 博客思聽中文有聲書摘，台湾的书摘Podcast，都是不错的商业类书籍，不过实在是短了点，一般一本书只有30分钟左右的内容。 EnglishPod，英语学习的Podcast。]]></description>
			<content:encoded><![CDATA[<p>开始订阅和收听Podcast，看了一些blog，感觉Podcast可以成为一种提高时间效率和学习的新的工具，利用Podcast，可以多线程工作，在跑步的时候学习，写Blog时候听新闻。</p>
<p>之前也尝试过收听音乐类的Podcast，不觉得好，一是有广告，造成中断很多，而是我听歌本来就那么几首，所以大部分觉得不好听，于是当时不太看好。</p>
<p>这两天，尝试使用Podcast听一些学习类新闻类的节目，itunes订阅，边上网边听，发现很不错。对Podcast的未来，还是认为内容很重要，或者说，质量很重要，这一点上，Podcast需要的不是所谓Web 2.0那种的用户创建内容，获得高质量的内容，非常非常重要。业余的作者，或许可以写出不错的Blog，浏览者也会很多，生活性的内容也会有朋友来看。但是，Podcast的话，业余一点，我认为能听下去的人很少。没有听众，创作者也会失去兴趣继续制作，于是，产业量就会破坏了。</p>
<p>我的想法是，远程教育，付费内容，可以构成Podcast的产业，Apple Store的模式，可以获得成功。当然，版权始终是一个问题，可能，还是需要内容免费，依靠增值的服务，不过，对于高质量的Podcast，我是愿意付费订阅的。</p>
<p><a href="http://www.apple.com/itunes/">Itunes</a>用起来很不错，都让我有冲动去买ipod了，不过貌似CPU占用率一上去就会有破声。<br />
<a href="http://www.podlook.com/">Podlook</a>做得很不错，上面能找到不少不错的Podcast。</p>
<p>我订阅了这几个：<br />
<a href="http://www.podlook.com/channel/16093">锵锵三人行</a>，发现很好玩，听录音的好处在于同时可以干别的事。<br />
<a href="http://www.podlook.com/channel/11669">ITC: All Programs</a>，IT Conversation的一些录音，适合联系IT类的听力和了解业界前沿的信息，不过我还没仔细听过。<br />
<a href="http://www.podlook.com/channel/15334">博客思聽中文有聲書摘</a>，台湾的书摘Podcast，都是不错的商业类书籍，不过实在是短了点，一般一本书只有30分钟左右的内容。<br />
<a href="http://www.podlook.com/channel/11549">EnglishPod</a>，英语学习的Podcast。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2006/05/11/podcast%e5%88%9d%e4%bd%93%e9%aa%8c/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>辩论与计算机科学（纯属娱乐/无主题）</title>
		<link>http://www.xuwenhao.com/2006/03/22/%e8%be%a9%e8%ae%ba%e4%b8%8e%e8%ae%a1%e7%ae%97%e6%9c%ba%e7%a7%91%e5%ad%a6%ef%bc%88%e7%ba%af%e5%b1%9e%e5%a8%b1%e4%b9%90%e6%97%a0%e4%b8%bb%e9%a2%98%ef%bc%89/</link>
		<comments>http://www.xuwenhao.com/2006/03/22/%e8%be%a9%e8%ae%ba%e4%b8%8e%e8%ae%a1%e7%ae%97%e6%9c%ba%e7%a7%91%e5%ad%a6%ef%bc%88%e7%ba%af%e5%b1%9e%e5%a8%b1%e4%b9%90%e6%97%a0%e4%b8%bb%e9%a2%98%ef%bc%89/#comments</comments>
		<pubDate>Tue, 21 Mar 2006 16:54:47 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/60</guid>
		<description><![CDATA[我承认我很无聊，又写和辩论有关的blog。 看到前室友写的关于辩论的文章，有点手痒。 辩论赛是不是一种有意义的活动，大家疑义很多，从我的观点来看，还是有的。事实上，如果没有看过某神的比赛和文章的话，在参加了很多场，观看了很多场的比赛之后，我可能也会对辩论赛的意义存疑，不过，现在，不会了。 这个有意义的活动不是指所有的辩题和所有的比赛或者所有的人，只是从纯粹的研究角度来说。很多辩题毫无意义，或者说基本没有，比如类似于&#8221;男追女女追男&#8221;这样的。有些比赛毫无意义，比如暗箱操作外加评委水平及其低下。有些人的比赛毫无意义，比如只会朗诵、拿卡片、背名人名言。 但是，如果你，真的是带着思考问题的方式，去讨论一些价值性的命题的话，是很有意思的，比如说某神举的一个例子。 本来辩论也好，辩论赛也好，没有什么真假对错之分，而价值性的辩题，尤其很多时候和我们周围的生活息息相关的时候，可以有很多有趣的假设，让你重新从拥有不同价值观的人的角度去思考问题，然后再推而广之，有可以去讨论社会不同群体之间的价值观的对抗，实在是很过瘾。对不起跑题了。 如果把这样的一个辩题拆解开来看，可能有点像Configurator（Configurator是一种类型的企业级软件，举个例子，比如像Ford这样的汽车公司，在提供给消费者自主配置的汽车型号的时候，所存在的约束，比如微型车只能用四缸发动机，卡车不能有四开门的，在约束条件较少的时候，是很简单的问题，但是当约束达到上千条乃至上万条，同时互相之间还有大量的约束和关联的时候，就是一个复杂的企业及系统了）。简而言之，这些辩题是一种约束的集合，放到某一个特定的环境和特定的人身上，可能有非常简单的A-〉B这样的结论（比如说 父慈&#8211;〉子孝），但是这只是一种理想化的情况，当前提套用到不同的人身上，在不同的社会环境下，乃至不同的时间和文化背景，约束条件就起了变化，于是A-〉B不会再简单的成立（比如说 母不慈，父慈&#8211;〉子孝 是否成立？），当然，我据的例子不太恰当，但是希望大家能理解。这样的不同背景，不同的社会环境，不同价值观的人的存在，使得对于前提推出结论的约束存在上千种，也使得A能否推导出B变成了一个需要、也值得讨论的问题。 对于准备辩论赛的人需要做些什么呢，它需要去遍历一遍这样的约束和他的结论，他有两种选择，深度优先和广度优先，深度优先是先深入研究一两种情况，深入地去挖掘这些约束背后的社会意义和在这个辩题的背景下存在的价值；广度优先先是去讨论对于不同的情况分类的对策。两者只是准备策略的不同，没有高下之分，最终目的是对于整个辩题能有一个全面的理解。由于时间有限，遍历不能够完成，所以我们需要在遍历中进行剪枝，即去除意义不大、过于特殊等等的讨论。同时，也要对遍历路径的权重加以考虑，尽量把时间花在讨论对自己一方阐述最有效果的路径以及对方最有可能阐述的路径上，这有点类似于AI中的A*树（我没有记错吧？）。这样的一个准备，是一支队伍所需要的基本功，如果做不到，那是连业余队也算不上了。但是这样的准备，充其量只能算是逻辑层面上的表述，还算不上高水平。 大量的约束虽然可以这样来讨论，但是这样的讨论的问题在于，约束之间的关联考虑的不够，整个辩题的准备感觉支离破碎，虽然可能底线做得不错，逻辑上也讲得通，甚至可以做得很出彩。但是对于问题的深度挖掘和真正的价值层面的讨论还算不上。这个时候我们需要的是什么？是对于约束进行数据挖掘、聚类分析，找出在最符合背景条件下最大的可能结论，然后加以阐释。到了这个层面，就有点真正的所谓思辨的乐趣了。 我写了些什么？不知道…… （未完待续）]]></description>
			<content:encoded><![CDATA[<p>我承认我很无聊，又写和辩论有关的blog。</p>
<p>看到前室友写的<a href="http://neverisland.blogbus.com/logs/2006/03/2095642.html" title="NeverIsland">关于辩论的文章</a>，有点手痒。</p>
<p>辩论赛是不是一种有意义的活动，大家疑义很多，从我的观点来看，还是有的。事实上，如果没有看过<a href="http://www.wretch.cc/blog/JonasHwang" title="满座衣冠似雪">某神</a>的比赛和文章的话，在参加了很多场，观看了很多场的比赛之后，我可能也会对辩论赛的意义存疑，不过，现在，不会了。</p>
<p>这个有意义的活动不是指所有的辩题和所有的比赛或者所有的人，只是从纯粹的研究角度来说。很多辩题毫无意义，或者说基本没有，比如类似于&#8221;男追女女追男&#8221;这样的。有些比赛毫无意义，比如暗箱操作外加评委水平及其低下。有些人的比赛毫无意义，比如只会朗诵、拿卡片、背名人名言。</p>
<p>但是，如果你，真的是带着思考问题的方式，去讨论一些价值性的命题的话，是很有意思的，比如说某神举的一个例子。</p>
<p>本来辩论也好，辩论赛也好，没有什么真假对错之分，而价值性的辩题，尤其很多时候和我们周围的生活息息相关的时候，可以有很多有趣的假设，让你重新从拥有不同价值观的人的角度去思考问题，然后再推而广之，有可以去讨论社会不同群体之间的价值观的对抗，实在是很过瘾。对不起跑题了。</p>
<p>如果把这样的一个辩题拆解开来看，可能有点像Configurator（Configurator是一种类型的企业级软件，举个例子，比如像Ford这样的汽车公司，在提供给消费者自主配置的汽车型号的时候，所存在的约束，比如微型车只能用四缸发动机，卡车不能有四开门的，在约束条件较少的时候，是很简单的问题，但是当约束达到上千条乃至上万条，同时互相之间还有大量的约束和关联的时候，就是一个复杂的企业及系统了）。简而言之，这些辩题是一种约束的集合，放到某一个特定的环境和特定的人身上，可能有非常简单的A-〉B这样的结论（比如说 父慈&#8211;〉子孝），但是这只是一种理想化的情况，当前提套用到不同的人身上，在不同的社会环境下，乃至不同的时间和文化背景，约束条件就起了变化，于是A-〉B不会再简单的成立（比如说 母不慈，父慈&#8211;〉子孝 是否成立？），当然，我据的例子不太恰当，但是希望大家能理解。这样的不同背景，不同的社会环境，不同价值观的人的存在，使得对于前提推出结论的约束存在上千种，也使得A能否推导出B变成了一个需要、也值得讨论的问题。</p>
<p>对于准备辩论赛的人需要做些什么呢，它需要去遍历一遍这样的约束和他的结论，他有两种选择，深度优先和广度优先，深度优先是先深入研究一两种情况，深入地去挖掘这些约束背后的社会意义和在这个辩题的背景下存在的价值；广度优先先是去讨论对于不同的情况分类的对策。两者只是准备策略的不同，没有高下之分，最终目的是对于整个辩题能有一个全面的理解。由于时间有限，遍历不能够完成，所以我们需要在遍历中进行剪枝，即去除意义不大、过于特殊等等的讨论。同时，也要对遍历路径的权重加以考虑，尽量把时间花在讨论对自己一方阐述最有效果的路径以及对方最有可能阐述的路径上，这有点类似于AI中的A*树（我没有记错吧？）。这样的一个准备，是一支队伍所需要的基本功，如果做不到，那是连业余队也算不上了。但是这样的准备，充其量只能算是逻辑层面上的表述，还算不上高水平。</p>
<p>大量的约束虽然可以这样来讨论，但是这样的讨论的问题在于，约束之间的关联考虑的不够，整个辩题的准备感觉支离破碎，虽然可能底线做得不错，逻辑上也讲得通，甚至可以做得很出彩。但是对于问题的深度挖掘和真正的价值层面的讨论还算不上。这个时候我们需要的是什么？是对于约束进行数据挖掘、聚类分析，找出在最符合背景条件下最大的可能结论，然后加以阐释。到了这个层面，就有点真正的所谓思辨的乐趣了。</p>
<p>我写了些什么？不知道……</p>
<p>（未完待续）</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2006/03/22/%e8%be%a9%e8%ae%ba%e4%b8%8e%e8%ae%a1%e7%ae%97%e6%9c%ba%e7%a7%91%e5%ad%a6%ef%bc%88%e7%ba%af%e5%b1%9e%e5%a8%b1%e4%b9%90%e6%97%a0%e4%b8%bb%e9%a2%98%ef%bc%89/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>可用性设计(2)</title>
		<link>http://www.xuwenhao.com/2006/02/19/%e5%8f%af%e7%94%a8%e6%80%a7%e8%ae%be%e8%ae%a12/</link>
		<comments>http://www.xuwenhao.com/2006/02/19/%e5%8f%af%e7%94%a8%e6%80%a7%e8%ae%be%e8%ae%a12/#comments</comments>
		<pubDate>Sun, 19 Feb 2006 12:07:11 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/46</guid>
		<description><![CDATA[周六，pretty同学口腔溃疡，买来了易可贴。取出一粒药，研究哪一面该粘在手指上，我看了一眼，说白面，pretty同学看了一下说明书，是黄面。然后pretty同学问，为什么取出的时候朝上的一面为什么不是黄面呢？ 又是个可用性问题，或许这家厂家没有遇到过因为把药片翻了个面的患者，由于没洗手，最后因为细菌感染造成口腔溃疡更加严重的案例。]]></description>
			<content:encoded><![CDATA[<p>周六，pretty同学口腔溃疡，买来了易可贴。取出一粒药，研究哪一面该粘在手指上，我看了一眼，说白面，pretty同学看了一下说明书，是黄面。然后pretty同学问，为什么取出的时候朝上的一面为什么不是黄面呢？</p>
<p>又是个可用性问题，或许这家厂家没有遇到过因为把药片翻了个面的患者，由于没洗手，最后因为细菌感染造成口腔溃疡更加严重的案例。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2006/02/19/%e5%8f%af%e7%94%a8%e6%80%a7%e8%ae%be%e8%ae%a12/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>可用性设计(1)</title>
		<link>http://www.xuwenhao.com/2006/02/19/%e5%8f%af%e7%94%a8%e6%80%a7%e8%ae%be%e8%ae%a11/</link>
		<comments>http://www.xuwenhao.com/2006/02/19/%e5%8f%af%e7%94%a8%e6%80%a7%e8%ae%be%e8%ae%a11/#comments</comments>
		<pubDate>Sun, 19 Feb 2006 12:01:49 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/45</guid>
		<description><![CDATA[周五，去联华买东西，过马路。红灯停，绿灯行。发现东西向的绿灯变红灯之后，要过5秒钟，南北向的红灯才变成绿灯。然后，南北向的绿灯将维持12秒钟。南北向的绿灯便红灯之后，也要过5秒钟，东西向的红灯，才会变成绿灯。然后，东西向的绿灯将维持18秒钟。 问题是，我这个190公分的大汉，以正常步速过马路，南北向需要18秒左右，东西向路长一点，需要25秒左右。 政府部门的哪个猪头设计的这种红绿灯？逼我闯红灯么。]]></description>
			<content:encoded><![CDATA[<p>周五，去联华买东西，过马路。红灯停，绿灯行。发现东西向的绿灯变红灯之后，要过5秒钟，南北向的红灯才变成绿灯。然后，南北向的绿灯将维持12秒钟。南北向的绿灯便红灯之后，也要过5秒钟，东西向的红灯，才会变成绿灯。然后，东西向的绿灯将维持18秒钟。</p>
<p>问题是，我这个190公分的大汉，以正常步速过马路，南北向需要18秒左右，东西向路长一点，需要25秒左右。</p>
<p>政府部门的哪个猪头设计的这种红绿灯？逼我闯红灯么。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2006/02/19/%e5%8f%af%e7%94%a8%e6%80%a7%e8%ae%be%e8%ae%a11/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google股价下跌是理所当然的事</title>
		<link>http://www.xuwenhao.com/2006/02/05/google%e8%82%a1%e4%bb%b7%e4%b8%8b%e8%b7%8c%e6%98%af%e7%90%86%e6%89%80%e5%bd%93%e7%84%b6%e7%9a%84%e4%ba%8b/</link>
		<comments>http://www.xuwenhao.com/2006/02/05/google%e8%82%a1%e4%bb%b7%e4%b8%8b%e8%b7%8c%e6%98%af%e7%90%86%e6%89%80%e5%bd%93%e7%84%b6%e7%9a%84%e4%ba%8b/#comments</comments>
		<pubDate>Sun, 05 Feb 2006 09:09:27 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/archives/22</guid>
		<description><![CDATA[在我上班无事可做百无聊赖的时候，在我的bloglines上看见了keso同志春节期间更新频率大大下降的blog上出现了这样一篇文章东拉西扯：Google应该赚多少钱。keso同志仍然充分表现了他是个google的fans，然而其中这样一句话我却不敢苟同：“但它是Google，投资者不愿意把它看作一家普通的上市公司，它必须持续地超常规增长，尤其是持续地超常规赚钱。” 似乎google股价下滑是别人没眼光，别人做的不对，事实上，google股价下滑，是基本的价值回归和反映。google第四季度的财报其实很简单，增速放缓，纯收益较上一季度下滑。这样的情况下，股价下跌本来就是很正常的，更何况，google的股价本来就是依靠高速成长支撑的。即使下跌后的382美元，其市盈率仍然是居高不下，第四季度的每股收益为1.22美元，那么一年估算为5美元的话，市盈率也高达76倍，这个数字其实说明了一点，如果下一季度增长仍然放缓，股价肯定仍然会下跌，baidu可以跌，刘韧可以继续看跌。为什么google跌搞得好像都是别人的错呢？ keso说google是天才公司，我说不是，google的确雇了很多天才，google也有很多很好的产品，但是对于公司来说，赚钱的多少是衡量其健康状况的最佳指标，google到现在也没有找到除了搜索广告之外的强有力的增长点，光有一些有特色的产品有什么用？再天才，也不是天才公司。 google现在的文化泡沫味儿已经起来了，从厨子到宠物，尽管目前很吸引人，但是好像几年以前泡沫的时候不少公司的免费啤酒和桌上足球还有跑车也很吸引人，现在活下来的又有几个？ keso说google要对三部分人负责：股东、客户和员工。但是为什么就忘了google的“供应商”呢？从前的Adwards说你作弊你就作弊，没做也做，算是对为google发布广告的个人站长负责么？说白了，保护的始终是自己的经济利益，在国内加上过滤也是一样，和门始终关不上、人为财死跳槽的李开复同志一样，终究是利益为先。google是一家好公司，但是为之套上太多道德的外衣和枷锁，实在只能是自欺欺人罢了。]]></description>
			<content:encoded><![CDATA[<p>在我上班无事可做百无聊赖的时候，在我的bloglines上看见了<a href="http://blog.donews.com/keso">keso</a>同志春节期间更新频率大大下降的blog上出现了这样一篇文章<a href="http://blog.donews.com/keso/archive/2006/02/05/715629.aspx">东拉西扯：Google应该赚多少钱</a>。keso同志仍然充分表现了他是个google的fans，然而其中这样一句话我却不敢苟同：“但它是Google，投资者不愿意把它看作一家普通的上市公司，它必须持续地超常规增长，尤其是持续地超常规赚钱。”</p>
<p>似乎google股价下滑是别人没眼光，别人做的不对，事实上，google股价下滑，是基本的价值回归和反映。<a href="http://tech.sina.com.cn/i/2006-02-01/0822831896.shtml">google第四季度的财报</a>其实很简单，增速放缓，纯收益较上一季度下滑。这样的情况下，股价下跌本来就是很正常的，更何况，google的股价本来就是依靠高速成长支撑的。即使下跌后的382美元，其市盈率仍然是居高不下，<font id="zoom" class="f14">第四季度的每股收益为1.22美元，那么一年估算为5美元的话，市盈率也高达76倍，这个数字其实说明了一点，</font>如果下一季度增长仍然放缓，股价肯定仍然会下跌，baidu可以跌，<a href="http://my.donews.com/liuren/2006/02/03/%e7%99%be%e5%ba%a6%e8%b7%8c%e5%90%91%e4%bd%95%e6%96%b9%ef%bc%9f/">刘韧可以继续看跌</a>。为什么google跌搞得好像都是别人的错呢？</p>
<p>keso说google是天才公司，我说不是，google的确雇了很多天才，google也有很多很好的产品，但是对于公司来说，赚钱的多少是衡量其健康状况的最佳指标，google到现在也没有找到除了搜索广告之外的强有力的增长点，光有一些有特色的产品有什么用？再天才，也不是<span style="color: DarkRed">天才公司</span>。 google现在的文化泡沫味儿已经起来了，从厨子到宠物，尽管目前很吸引人，但是好像几年以前泡沫的时候不少公司的免费啤酒和桌上足球还有跑车也很吸引人，现在活下来的又有几个？</p>
<p>keso说google要对三部分人负责：股东、客户和员工。但是为什么就忘了google的“供应商”呢？从前的Adwards说你作弊你就作弊，没做也做，算是对为google发布广告的个人站长负责么？说白了，保护的始终是自己的经济利益，在国内加上过滤也是一样，和门始终关不上、人为财死跳槽的李开复同志一样，终究是利益为先。google是一家好公司，但是为之套上太多道德的外衣和枷锁，实在只能是自欺欺人罢了。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2006/02/05/google%e8%82%a1%e4%bb%b7%e4%b8%8b%e8%b7%8c%e6%98%af%e7%90%86%e6%89%80%e5%bd%93%e7%84%b6%e7%9a%84%e4%ba%8b/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>不要滥用Ajax，搞清楚状况先</title>
		<link>http://www.xuwenhao.com/2006/01/30/%e4%b8%8d%e8%a6%81%e6%bb%a5%e7%94%a8ajax%ef%bc%8c%e6%90%9e%e6%b8%85%e6%a5%9a%e7%8a%b6%e5%86%b5%e5%85%88/</link>
		<comments>http://www.xuwenhao.com/2006/01/30/%e4%b8%8d%e8%a6%81%e6%bb%a5%e7%94%a8ajax%ef%bc%8c%e6%90%9e%e6%b8%85%e6%a5%9a%e7%8a%b6%e5%86%b5%e5%85%88/#comments</comments>
		<pubDate>Sun, 29 Jan 2006 16:05:41 +0000</pubDate>
		<dc:creator>Stanley Xu</dc:creator>
				<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://www.xuwenhao.com/2006/01/30/%e4%b8%8d%e8%a6%81%e6%bb%a5%e7%94%a8ajax%ef%bc%8c%e6%90%9e%e6%b8%85%e6%a5%9a%e7%8a%b6%e5%86%b5%e5%85%88/</guid>
		<description><![CDATA[决定开始写一些技术小文章，一是总结过去遇到的一些问题的经验，而是锻炼一下写技术文章的能力，争取过两年能混点稿费啥的。 Ajax在过去的一年，可谓大红大紫，以至于很多时候，我们在考虑到减少网络流量的时候，减少页面刷新的时候，第一反应都是，“用Ajax实现吧”。 但是，且慢，是不是所有的都有必要用到Ajax呢？是不是有些时候，不用Ajax，其实一样能够简单有效的实现需求呢？当然，前一段时间，我就遇到这么一个例子。 业务需求是这样的，我们为某公司内部的Call Center建立一个Knowledge Base（以下简称为KB），以帮助接线员迅速查找到所需要的产品资料，告诉用户。用户的产品资料是一个三层的结构，包括Brand, Model和Trim，约有20个左右的Brand，每个Brand下有多个Model，每个Model下还有数个Trim，每个Trim下，则包含了大量的所需要的产品资料信息。接线员在使用KB的时候，先从一个select box选择Brand，然后再从另一个select box中选择该Brand下的Model，最后再从一个select box中选择到该Model下的Trim，最后点击一个button，获取该Trim的所有信息。 当时在接到这个KB的时候，时间紧迫，于是，在熬了一个通宵之后，做出了第一个版本，将结果发到美国，等待反馈，反馈的结果则是，页面performance不够好，每次选完Trim之后等待页面刷新，要很长时间。 这个结果在我们的预料之中，因为，由于时间上的限制，在实现Brand，Model，Trim的三层select box的动态刷新的时候，没有自己从头实现，而是参考了另一个项目组A的代码。实现的方法是在javascript通过二维数组保存所有的Brand，Model和Trim的关联信息，动态生成select box中的内容。由于我们的Brand，Model，Trim的关联信息远远比A的数量要多，因为A中只有Brand和Model的两层关联信息，所以，在他们那边不成问题的页面大小问题，在我们这边就成了大问题。事实上，我们存在javascript数组中的信息，高达300k，而整个页面的其他部分的大小之和，也不超过30k。 问题应该如何解决呢？方案有很多种，比如，我们可以用Ajax重写三层select box的刷新，但是，时间有限，代码改动也会比较大；或者，我们可以将javascript的关联信息，单独写在一个js文件中，这样，一般情况下，浏览器会将其存在cache中，每次数据传输的流量就不会过大，但是cache本身就不牢靠，而且这样在后台数据更新了之后，浏览其中可能还是过时的cache信息。 考虑再三之后，和同事讨论研究了一下，决定采用Ajax来写获得Trim具体信息的部分，这样，只需要将原来的页面刷新中，采用form提交，刷新整个页面，改成通过发送一个ajax-request，由ajax-response更新Trim具体信息区域即可，这样，在第一次获得页面之后，以后都不用重新从服务器端去读取Brand，Model，Trim的层级关联信息，也就解决了performance的问题。 于是，我采用了rico包，花了一个下午实现了这个功能，但是发现还是有问题，由于rico包对特殊字符的支持不好，我们不得不专门写了个程序，将所有从后台传递的字符转成unicode再传过来，看起来，问题到这里已经解决了，于是测试一下，似乎有些时候行，有些时候不行，捣腾了好一会儿，没有修改代码，似乎，问题是解决了，但是心里还是不放心，因为之前用rico写中文站点的时候，遇到过在Firefox下即使所有字符都转成unicode，仍然有些字符不能传到前台的问题。而大量的Trim信息，我们不可能手工一个一个测过来，写脚本测，时间也不太充裕了…… 最后，我们怎么解决问题的呢？其实很简单，我们为什么要用Ajax？事实上，我们最后是采用了frameset的办法，一个frame里放的是三层关联信息的select box，另一个frame里，放Trim的具体信息页面，只要将上面的form的target设为下面的form，那么每次就是刷新Trim的具体信息，所需要的，只是将原来一个页面里的代码，放到两个frame里……而之前，我们为什么会去考虑到Ajax这种啥办法呢？ 总结一下，之所以会花大量的时间去做无用功，一是习惯性的使用所谓的优秀技术，总觉得，啊，要用Ajax；二是没有仔细分析清楚需求，我们所要得，不是不刷新页面，而是减少数据传输量，刷不刷新页面，是无所谓的。事实上，在Web的设计和实现的时候，我们会遇到大量的类似问题，所以，分析需求，考虑到所有最简单最低级的技术，是很有价值的。有时候，我们要的是SEO，要google搜到我们，不能用Ajax；有时候，我们要良好的中文支持，最好别用Ajax；有时候，我们只是要减少数据传输量，framset已经足够。Ajax不是万能药，有种种的缺陷和限制，适用的情况，其实并没有那么多。]]></description>
			<content:encoded><![CDATA[<p>决定开始写一些技术小文章，一是总结过去遇到的一些问题的经验，而是锻炼一下写技术文章的能力，争取过两年能混点稿费啥的。</p>
<p>Ajax在过去的一年，可谓大红大紫，以至于很多时候，我们在考虑到减少网络流量的时候，减少页面刷新的时候，第一反应都是，“用Ajax实现吧”。</p>
<p>但是，且慢，是不是所有的都有必要用到Ajax呢？是不是有些时候，不用Ajax，其实一样能够简单有效的实现需求呢？当然，前一段时间，我就遇到这么一个例子。</p>
<p>业务需求是这样的，我们为某公司内部的Call Center建立一个Knowledge Base（以下简称为KB），以帮助接线员迅速查找到所需要的产品资料，告诉用户。用户的产品资料是一个三层的结构，包括Brand, Model和Trim，约有20个左右的Brand，每个Brand下有多个Model，每个Model下还有数个Trim，每个Trim下，则包含了大量的所需要的产品资料信息。接线员在使用KB的时候，先从一个select box选择Brand，然后再从另一个select box中选择该Brand下的Model，最后再从一个select box中选择到该Model下的Trim，最后点击一个button，获取该Trim的所有信息。</p>
<p>当时在接到这个KB的时候，时间紧迫，于是，在熬了一个通宵之后，做出了第一个版本，将结果发到美国，等待反馈，反馈的结果则是，页面performance不够好，每次选完Trim之后等待页面刷新，要很长时间。</p>
<p>这个结果在我们的预料之中，因为，由于时间上的限制，在实现Brand，Model，Trim的三层select box的动态刷新的时候，没有自己从头实现，而是参考了另一个项目组A的代码。实现的方法是在javascript通过二维数组保存所有的Brand，Model和Trim的关联信息，动态生成select box中的内容。由于我们的Brand，Model，Trim的关联信息远远比A的数量要多，因为A中只有Brand和Model的两层关联信息，所以，在他们那边不成问题的页面大小问题，在我们这边就成了大问题。事实上，我们存在javascript数组中的信息，高达300k，而整个页面的其他部分的大小之和，也不超过30k。</p>
<p>问题应该如何解决呢？方案有很多种，比如，我们可以用Ajax重写三层select box的刷新，但是，时间有限，代码改动也会比较大；或者，我们可以将javascript的关联信息，单独写在一个js文件中，这样，一般情况下，浏览器会将其存在cache中，每次数据传输的流量就不会过大，但是cache本身就不牢靠，而且这样在后台数据更新了之后，浏览其中可能还是过时的cache信息。</p>
<p>考虑再三之后，和同事讨论研究了一下，决定采用Ajax来写获得Trim具体信息的部分，这样，只需要将原来的页面刷新中，采用form提交，刷新整个页面，改成通过发送一个ajax-request，由ajax-response更新Trim具体信息区域即可，这样，在第一次获得页面之后，以后都不用重新从服务器端去读取Brand，Model，Trim的层级关联信息，也就解决了performance的问题。</p>
<p>于是，我采用了<a href="http://openrico.org/rico">rico</a>包，花了一个下午实现了这个功能，但是发现还是有问题，由于rico包对特殊字符的支持不好，我们不得不专门写了个程序，将所有从后台传递的字符转成unicode再传过来，看起来，问题到这里已经解决了，于是测试一下，似乎有些时候行，有些时候不行，捣腾了好一会儿，没有修改代码，似乎，问题是解决了，但是心里还是不放心，因为之前用rico写中文站点的时候，遇到过在Firefox下即使所有字符都转成unicode，仍然有些字符不能传到前台的问题。而大量的Trim信息，我们不可能手工一个一个测过来，写脚本测，时间也不太充裕了……</p>
<p>最后，我们怎么解决问题的呢？其实很简单，我们为什么要用Ajax？事实上，我们最后是采用了frameset的办法，一个frame里放的是三层关联信息的select box，另一个frame里，放Trim的具体信息页面，只要将上面的form的target设为下面的form，那么每次就是刷新Trim的具体信息，所需要的，只是将原来一个页面里的代码，放到两个frame里……而之前，我们为什么会去考虑到Ajax这种啥办法呢？</p>
<p>总结一下，之所以会花大量的时间去做无用功，一是<span style="color: blue">习惯性的使用所谓的优秀技术</span>，总觉得，啊，要用Ajax；二是没有仔细分析清楚需求，<span style="color: blue">我们所要得，不是不刷新页面，而是减少数据传输量，</span>刷不刷新页面，是无所谓的。事实上，在Web的设计和实现的时候，我们会遇到大量的类似问题，所以，分析需求，<span style="color: blue">考虑到所有最简单最低级的技术</span>，是很有价值的。有时候，我们要的是SEO，要google搜到我们，不能用Ajax；有时候，我们要良好的中文支持，最好别用Ajax；有时候，我们只是要减少数据传输量，framset已经足够。<strong><span style="color: DarkRed">Ajax不是万能药，有种种的缺陷和限制，适用的情况，其实并没有那么多。</span></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.xuwenhao.com/2006/01/30/%e4%b8%8d%e8%a6%81%e6%bb%a5%e7%94%a8ajax%ef%bc%8c%e6%90%9e%e6%b8%85%e6%a5%9a%e7%8a%b6%e5%86%b5%e5%85%88/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

