﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-冬Blog</title><link>http://www.cnblogs.com/yuandong/</link><description>醉心技术、醉心生活</description><language>zh-cn</language><lastBuildDate>Sat, 30 Aug 2008 03:58:05 GMT</lastBuildDate><pubDate>Sat, 30 Aug 2008 03:58:05 GMT</pubDate><ttl>60</ttl><item><title>网路爬虫（3）：url索引</title><link>http://www.cnblogs.com/yuandong/archive/2008/08/28/Web_Spider_Url_Index.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Thu, 28 Aug 2008 00:37:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/08/28/Web_Spider_Url_Index.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1278275.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/08/28/Web_Spider_Url_Index.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1278275.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1278275.html</trackback:ping><description><![CDATA[   <p>url索引的作用是判断一个url是否被抓取过，采用的算法主要是MD5数字签名。</p> <p>假设一共要抓取的url不超过1亿条，用一个二进制的位表示一个url是否被抓取过，则至少需要1亿个位，我们管每一个位叫一个“槽”。考虑到MD5的算法是可能出现冲突（即不同的url算出来的MD5可能相同，这种概率很小），槽越少，冲突越明显，所以槽越多越好。但另一方面，还要考虑到占用内存的大小，因为在抓取的过程中，为了保证效率，所有的槽都需要载入内存。目前我使用的是2的28次方，即32M，相当于268435456（2.6亿）个槽。</p> <p>当要判断一个url是否已经抓取过的时候，只要判断该url经过MD5签名后的值所对应的槽是否标记为1即可。例如给出的url是：<a href="http://www.ouc.edu.cn/">http://www.ouc.edu.cn/</a>，经过128位的MD5签名后，得出的1073542761，则需要判断的就是第1073542761个槽是0还是1。同样的道理，当完成一个url的抓取后，要将对应的槽标记为1。</p> <p>存储槽的32M空间在内存是不连续的，因为操作系统很难划分出32M的连续内存空间，所以将其分为4096个段Segment，每段2048个32位整数，32*2048*4096=268435456。相当于一个整型的二维数组。</p> <p><a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/3url_838D/url_2.jpg"><img style="border: 0px none ;" alt="url" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/3url_838D/url_thumb.jpg" border="0" height="359" width="415"></a> </p> <p>我们使用32位的MD5作为签名，表示为一个整数。这个整数分为三部分，分别是段地址、段偏移和值地址。第5-16位表示段地址，17-27位表示段偏移，28-32位（最后5位，取值范围为2的5次方，即0-31）表示在整形值中的位置、即值地址。</p> <p><a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/3url_838D/url2_4.jpg"><img style="border: 0px none ;" alt="url2" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/3url_838D/url2_thumb_1.jpg" border="0" height="91" width="564"></a> </p> <p>当给定一个url的MD5值时，通过以下函数计算出其段地址：</p> <div class="csharpcode"><pre><span class="lnum">   1:  </span>unsigned <span class="kwrd">short</span> get_segment_index(unsigned <span class="kwrd">int</span> md5) {</pre><pre><span class="lnum">   2:  </span>    </pre><pre><span class="lnum">   3:  </span>    <span class="rem">//5-16位表示段地址</span></pre><pre><span class="lnum">   4:  </span>    </pre><pre><span class="lnum">   5:  </span>    unsigned <span class="kwrd">short</span> result;</pre><pre><span class="lnum">   6:  </span>    bzero(&amp;result, <span class="kwrd">sizeof</span>(unsigned <span class="kwrd">short</span>));</pre><pre><span class="lnum">   7:  </span>    memcpy(&amp;result, ((<span class="kwrd">char</span>*)&amp;md5) + 2, <span class="kwrd">sizeof</span>(unsigned <span class="kwrd">short</span>));</pre><pre><span class="lnum">   8:  </span>&nbsp;</pre><pre><span class="lnum">   9:  </span>    <span class="kwrd">return</span> result &amp; 0x0FFF;</pre><pre><span class="lnum">  10:  </span>}</pre></div>
<p>通过以下函数计算出其段偏移：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span>unsigned <span class="kwrd">short</span> get_segment_offset(unsigned <span class="kwrd">int</span> md5) {</pre><pre><span class="lnum">   2:  </span>    </pre><pre><span class="lnum">   3:  </span>    <span class="rem">//17-27位表示段偏移</span></pre><pre><span class="lnum">   4:  </span>    </pre><pre><span class="lnum">   5:  </span>    unsigned <span class="kwrd">short</span> result;</pre><pre><span class="lnum">   6:  </span>    bzero(&amp;result, <span class="kwrd">sizeof</span>(unsigned <span class="kwrd">short</span>));</pre><pre><span class="lnum">   7:  </span>    memcpy(&amp;result, ((<span class="kwrd">char</span>*)&amp;md5), <span class="kwrd">sizeof</span>(unsigned <span class="kwrd">short</span>));</pre><pre><span class="lnum">   8:  </span>&nbsp;</pre><pre><span class="lnum">   9:  </span>    <span class="kwrd">return</span> result &gt;&gt; 5;</pre><pre><span class="lnum">  10:  </span>}</pre></div>


<p>通过以下函数计算其值偏移：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span>unsigned <span class="kwrd">int</span> get_value(unsigned <span class="kwrd">int</span> md5) {</pre><pre><span class="lnum">   2:  </span>    </pre><pre><span class="lnum">   3:  </span>    <span class="rem">//28-32（最后5位）为表示值</span></pre><pre><span class="lnum">   4:  </span>    </pre><pre><span class="lnum">   5:  </span>    unsigned <span class="kwrd">int</span> result = 1;</pre><pre><span class="lnum">   6:  </span>    <span class="kwrd">return</span> result &lt;&lt; (md5 &amp; 0x0000001F);</pre><pre><span class="lnum">   7:  </span>}</pre></div>


<p>再得到段地址、段偏移和值偏移后，就通过一下函数判定该Url是否已被抓取：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">bool</span> is_url_crawled(<span class="kwrd">char</span>* url) {</pre><pre><span class="lnum">   2:  </span>&nbsp;</pre><pre><span class="lnum">   3:  </span>    <span class="rem">//将给出的url进行md5运算，取得对应的Value，于储存的Value按位与</span></pre><pre><span class="lnum">   4:  </span>    </pre><pre><span class="lnum">   5:  </span>    unsigned <span class="kwrd">int</span> url_md5 = md5(url);</pre><pre><span class="lnum">   6:  </span>    unsigned <span class="kwrd">short</span> segment_index = get_segment_index(url_md5);</pre><pre><span class="lnum">   7:  </span>    unsigned <span class="kwrd">short</span> segment_offset = get_segment_offset(url_md5);</pre><pre><span class="lnum">   8:  </span>    unsigned <span class="kwrd">int</span> <span class="kwrd">value</span> = get_value(url_md5);</pre><pre><span class="lnum">   9:  </span>    </pre><pre><span class="lnum">  10:  </span>    unsigned <span class="kwrd">int</span> result = (unsigned <span class="kwrd">int</span>)</pre><pre>                                 (url_index[segment_index][segment_offset] &amp; <span class="kwrd">value</span>);</pre><pre><span class="lnum">  11:  </span>&nbsp;</pre><pre><span class="lnum">  12:  </span>    <span class="kwrd">return</span> result &gt; 0 ? TRUE : FALSE;</pre><pre><span class="lnum">  13:  </span>}</pre></div>


<p>如果未被抓取，在完成抓取后，通过以下函数标记为已抓取：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">int</span> mark_url_as_crawled(<span class="kwrd">char</span>* url) {</pre><pre><span class="lnum">   2:  </span>&nbsp;</pre><pre><span class="lnum">   3:  </span>    <span class="rem">//取得段地址、段偏移和url对应的值</span></pre><pre><span class="lnum">   4:  </span>    unsigned <span class="kwrd">int</span> url_md5 = md5(url);</pre><pre><span class="lnum">   5:  </span>    unsigned <span class="kwrd">short</span> segment_index = get_segment_index(url_md5);</pre><pre><span class="lnum">   6:  </span>    unsigned <span class="kwrd">short</span> segment_offset = get_segment_offset(url_md5);</pre><pre><span class="lnum">   7:  </span>    unsigned <span class="kwrd">int</span> <span class="kwrd">value</span> = get_value(url_md5);</pre><pre><span class="lnum">   8:  </span>&nbsp;</pre><pre><span class="lnum">   9:  </span>    <span class="rem">//通过按位或标记url对应的位为已抓取</span></pre><pre><span class="lnum">  10:  </span>    url_index[segment_index][segment_offset] |= <span class="kwrd">value</span>;</pre><pre><span class="lnum">  11:  </span>    </pre><pre><span class="lnum">  12:  </span>    <span class="rem">//同步写入索引文件</span></pre><pre><span class="lnum">  13:  </span>    <span class="kwrd">value</span> = url_index[segment_index][segment_offset];</pre><pre><span class="lnum">  14:  </span>    <span class="kwrd">long</span> offset = (((<span class="kwrd">long</span>)segment_index) * SEGMENT_LENGTH + segment_offset) </pre><pre>                            * <span class="kwrd">sizeof</span>(unsigned <span class="kwrd">int</span>);</pre><pre><span class="lnum">  15:  </span>    <span class="kwrd">if</span>(fseek(index_file, offset, SEEK_SET) != 0)</pre><pre><span class="lnum">  16:  </span>        <span class="kwrd">return</span> -1;</pre><pre><span class="lnum">  17:  </span>    </pre><pre><span class="lnum">  18:  </span>    <span class="kwrd">if</span>(fwrite(&amp;<span class="kwrd">value</span>, <span class="kwrd">sizeof</span>(unsigned <span class="kwrd">int</span>), 1, index_file) != 1)</pre><pre><span class="lnum">  19:  </span>        <span class="kwrd">return</span> -1;    </pre><pre><span class="lnum">  20:  </span>    </pre><pre><span class="lnum">  21:  </span>    fflush(index_file);</pre><pre><span class="lnum">  22:  </span>    <span class="kwrd">return</span> 0;</pre><pre><span class="lnum">  23:  </span>}</pre></div>
<img src ="http://www.cnblogs.com/yuandong/aggbug/1278275.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41965/" target="_blank">[新闻]美国年轻人最喜欢的15大网站</a>]]></description></item><item><title>权限系统设计</title><link>http://www.cnblogs.com/yuandong/archive/2008/08/26/Power_System_Design.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Tue, 26 Aug 2008 08:37:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/08/26/Power_System_Design.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1276810.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/08/26/Power_System_Design.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1276810.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1276810.html</trackback:ping><description><![CDATA[   <h4><strong>1 需求</strong></h4> <p>目前我做的这个项目的权限的要求可以归结为以下几点：</p> <ol> <li>用户是基于角色的。每个用户属于，且仅属于一个角色。  </li><li>系统中存在至少一个超级用户，且该用户具有所有权限。只有超级用户具有用户管理权限。  </li><li>超级用户可以仅仅针对某一个人定义权限。  </li><li>对于权限的判断，有以下两种基本形式，其它形式是这两种形式的演化：  <ol> <li>不含参权限。例如用户是否具有添加用户、管理文章分类的权限等。  </li><li>含参权限。例如用户是否具有某一个类别的文章的管理权限，这里某一个类别即为参数。</li></ol></li></ol> <h4><strong>2 类</strong></h4> <p><a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/472cf93b9365_7B79/ClassDiagram_6.jpg"><img style="border: 0px none ;" alt="ClassDiagram" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/472cf93b9365_7B79/ClassDiagram_thumb_2.jpg" border="0" height="382" width="839"></a> </p> <p>其中：</p> <ol> <li>UserRole表示用户角色、User表示用户。  </li><li>User含有对UserRole的引用，表示用户属于哪个角色。  </li><li>UserRole和User都拥有一个权限Power，即拥有一个Power的引用。  </li><li>Power真正处理权限的判断，UserRole和User的HasPower方法最终委托给Power的HasPower方法。  </li><li>PowerItem描述的是系统中的权限项目。</li></ol> <h4><strong>3 调用</strong></h4> <p>不含参权限判断为：</p> <blockquote><pre class="csharpcode">User user = getUser();
<span class="kwrd">bool</span> isUserHasArticleClassManagePower = user.HasPower(PowerItem.ArticleClassManage);
</pre></blockquote>
<p>含参权限判断为</p>
<blockquote><pre class="csharpcode">User user = getUser();
<span class="kwrd">bool</span> isUserHasArticlePower = user.HasPower(PowerItem.ArticleManage, someArticleClassID);
</pre></blockquote>
<p>设置用户和用户组具有某一个权限为：</p>
<blockquote><pre class="csharpcode">User user = getUser();
UserRole userRole = getUserRole();
Power power = user.Power;  <span class="rem">//Or power = userRole.Power;</span>
power.SetPower(PowerItem.ArticleClassManage);
power.SetPower(PowerItem.ArticleManage, someAricleClassID);</pre></blockquote>
<p>清除用户或用户组的某一个权限为：</p>
<blockquote><pre class="csharpcode">User user = getUser();
UserRole userRole = getUserRole();
Power power = user.Power;  <span class="rem">//Or power = userRole.Power;</span>
power.ClearPower(PowerItem.ArticleClassManage);
power.ClearPower(PowerItem.ArticleManage, someAricleClassID);</pre></blockquote>
<h4><strong>4 实现</strong></h4>
<p>User的HasPower方法最终的实现如下：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">   2:  </span><span class="rem">/// 判断是否具有某一项权限</span></pre><pre><span class="lnum">   3:  </span><span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">   4:  </span><span class="rem">/// &lt;param name="powerType"&gt;权限类别&lt;/param&gt;</span></pre><pre><span class="lnum">   5:  </span><span class="rem">/// &lt;param name="param"&gt;判断所需要的参数&lt;/param&gt;</span></pre><pre><span class="lnum">   6:  </span><span class="rem">/// &lt;returns&gt;是否具有该权限&lt;/returns&gt;</span></pre><pre><span class="lnum">   7:  </span><span class="kwrd">public</span> <span class="kwrd">bool</span> HasPower(PowerItem powerType, <span class="kwrd">object</span> param)</pre><pre><span class="lnum">   8:  </span>{</pre><pre><span class="lnum">   9:  </span>    <span class="rem">//超级用户拥有所有权限</span></pre><pre><span class="lnum">  10:  </span>    <span class="kwrd">if</span> (_IsSuper) <span class="kwrd">return</span> <span class="kwrd">true</span>;    </pre><pre><span class="lnum">  11:  </span>&nbsp;</pre><pre><span class="lnum">  12:  </span>    <span class="rem">//如果该用户是自定义权限，则使用自身的权限进行判断，</span></pre><pre><span class="lnum">  13:  </span>    <span class="rem">//否则，使用对应角色的权限进行判断</span></pre><pre><span class="lnum">  14:  </span>    <span class="kwrd">if</span> (_IsCustomPower)</pre><pre><span class="lnum">  15:  </span>        <span class="kwrd">return</span> Power.HasPower(powerType, param);</pre><pre><span class="lnum">  16:  </span>    <span class="kwrd">else</span></pre><pre><span class="lnum">  17:  </span>        <span class="kwrd">return</span> _UserRole.Entity.HasPower(powerType, param);</pre><pre><span class="lnum">  18:  </span>}</pre></div>
<p>UserRole的HasPower方法比较简单，仅仅是委托给其Power成员的HasPower方法：</p>
<blockquote><pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">bool</span> HasPower(PowerItem powerType, <span class="kwrd">object</span> param)
{
    <span class="kwrd">return</span> <span class="kwrd">this</span>.Power.HasPower(powerType, param);
}</pre></blockquote>
<p>Power类是判断权限的核心。</p>
<p>其成员Powers以"0,1,1,1"的方式保存了所有的权限。权限在该序列中的位置对应其权限项目的枚举值。例如PowerItem.ArticleClassManage的值是1，则序列"0,1,1,1"的第二个数（下标从零开始），表示是否具有ArticleClassManage权限。</p>
<p>对于含参的权限。例如PowerItem.ArticleManage，有一个成员AritcleClasses保存了所有判定为真的参数。如果该成员的值为“1,2,5”，则说明该用户或该角色具有ID为1,2,5的这三个文章分类的管理权限。</p>
<p>其HasPower方法为：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">bool</span> HasPower(PowerItem powerType, <span class="kwrd">object</span> param)</pre><pre><span class="lnum">   2:  </span>{</pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (!hasPower(powerType)) <span class="kwrd">return</span> <span class="kwrd">false</span>;</pre><pre><span class="lnum">   4:  </span>&nbsp;</pre><pre><span class="lnum">   5:  </span>    <span class="rem">//根据参数进行判断</span></pre><pre><span class="lnum">   6:  </span>    <span class="kwrd">switch</span> (powerType)</pre><pre><span class="lnum">   7:  </span>    {</pre><pre><span class="lnum">   8:  </span>        <span class="kwrd">case</span> PowerItem.ArticleManage:</pre><pre><span class="lnum">   9:  </span>            <span class="kwrd">return</span> hasPower(_AritcleClass, param);</pre><pre><span class="lnum">  10:  </span>        <span class="kwrd">default</span>:</pre><pre><span class="lnum">  11:  </span>            <span class="kwrd">return</span> <span class="kwrd">true</span>;</pre><pre><span class="lnum">  12:  </span>    }</pre><pre><span class="lnum">  13:  </span>}</pre></div>
<p>至于其中私有方法的细节，可以参考代码。</p>
<h4><strong>5 数据库</strong></h4>
<p><a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/472cf93b9365_7B79/%E6%95%B0%E6%8D%AE%E5%BA%93_2.jpg"><img style="border: 0px none ;" alt="数据库" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/472cf93b9365_7B79/%E6%95%B0%E6%8D%AE%E5%BA%93_thumb.jpg" border="0" height="512" width="829"></a> </p>
<h4><strong>6 示例代码</strong></h4>
<p><a href="http://files.cnblogs.com/yuandong/PowerDemo.rar">点击下载</a></p><img src ="http://www.cnblogs.com/yuandong/aggbug/1276810.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41964/" target="_blank">[新闻]2008年8月30日IT博客精选</a>]]></description></item><item><title>团队管理心得总结--回复别人的邮件</title><link>http://www.cnblogs.com/yuandong/archive/2008/08/07/1263162.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Thu, 07 Aug 2008 10:23:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/08/07/1263162.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1263162.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/08/07/1263162.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1263162.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1263162.html</trackback:ping><description><![CDATA[<p>===============================来信===============================</p> <p>袁冬，你好，我也是经常上博客园逛的一人，经常看到你的文章，写的很好，也深受启发，看了你的《团队职能》划分，我突然又想起了一直困扰着我的一个问题：团队人员水平不均要怎么处理？ </p><p>我现在在学校也有个小小的工作室，都是做web，从前是我一人和一位美工搞定，配合还算不错，但是现在下面有几人，水平不均匀，如果我不参于代码编写的话，他们往往会弄得一团糟，我可以很明显的感觉出来各个成员之间在工作时简直是隔离的，沟通太少，但我不知如何解决，当然，我也知道我本身的管理带领也有问题，但我也不知道如何解决。 </p><p>我对管理一个团队协作开发的经验还太少，你能否替我指点一二？我现在作为一个团队leader要注意哪些事情？我的工作是哪些？对于他们水平不均匀的问题我要如何解决？ </p><p>===============================回复===============================</p> <p>很不好意思，这么久才给回邮件，这两天事情比较多，见谅。</p> <p><br>听你的叙述，似乎你正处于从技术到管理的转型期，这是件不容易的事情，我在这个过程中也犯了不少错误，走了很多弯路。每个人成功的途径都不一样，适合我的方法不一定适合你，但是相信我失败的教训能给你一些启发。</p> <p><br>我觉得管理的第一要务是明确方向。我本科带团队，开始的时候就没有一个明确的方向，团队都不知道每天做的事情有什么意义。很难形成凝聚力，更不用说动力了。没有了凝聚力，团队就是不叫团队了，叫团伙更恰当；没有动力，团伙也只能一直是街头混混，成不了过江猛龙。所以我觉得第一个问题是解决你们团队的发展方向问题。我们本科那个团队（中国海洋大学爱特信息网）的方向是"发现人才、培养人才和输送人才"，初步目标是打造海大最强的技术团队，长远目标是打造教育系统内的知名团队。目前初步目标已经达成，长远目标还在努力。你们团队呢？</p> <p><br>第二，统一认识。也就是让大家认同你的想法。我刚带团队的时候自己想的很好，想当然的认为别人也是我这么想的，然后具体工作的时候发生了矛盾才发现大家的想法根本不一样！失去了很多优秀的队员。当然，如果别人确实和你的想法没有共同点，那就没办法了，道不同不相为谋嘛。要想统一认识比较难，我刚开始也没有很好的办法，在没有报酬、荣誉、学历等硬性约束的情况下，差不多也就只能靠一张嘴忽悠了。时不时的集体腐败一下通常能创造很好的谈话机会。</p> <p><br>要做到以上两点的主要手段就是身体力行和沟通。一般技术人员转成的管理人员，写程序方面都很让下面的人佩服，希望向你学习。相信你也有这个优点！我认为这点很重要，是个人领导魅力的重要来源，在没有硬性约束的情况就更加重要了。其实我倒是觉得管理没有硬性约束的团队是个好事儿，很锻炼人的领导能力！坚持做好这一点，更重要的是，让成员给觉得跟着你干也能成为和你一样的"了不起"的人。</p> <p><br>另一方面就是沟通，不断的持续的沟通，坚持不懈的向成员描绘一个愿景。这有点儿像洗脑，但其实不是，因为你所描绘的愿景是确实能够通过努力实现的，是真实的，不带有任何的欺骗性——你自己也坚信它会实现！这个愿景就是大家沿着你所指明的方向前进，最终能到达的理想生活，可能是自己的公司、可能是高薪的工作……</p> <p><br>上面这些有点儿大空假，呵呵，但我的的确确认为这些是最重要的，是根本性的问题（貌似根本性的问题说起来都有点儿大空假），其实我觉得一个管理人员能够真正在意识形态上成熟了，管理方法可以是随心所欲的，每个人管理风格都不一样。这类似于设计能力强了，什么语言熟悉一下，都可以写出优秀的程序。无招胜有招。</p> <p><br>说完了世界观，再谈谈方法论。</p> <p><br>先说你问的那个问题：团队人员水平不均要怎么处理。这个问题每个团队都有，我的办法是结对编程，这里具体的方法你可以参看我的两篇Blog：<a href="/yuandong/archive/2008/06/25/Pair_Programming_Practice.html">践行结对编程</a>和<a href="/yuandong/archive/2008/06/25/Something_About_Pair_Programming_Again.html">再论结对编程</a>，里面分析了团队成员水平不一致的情况。网上关于结对编程的资料很多，可以参考。我个人很喜欢敏捷的软件工程管理方法。推荐《敏捷软件开发，原则、模式与实践》这本书，涵盖工程学到具体实现。</p> <p><br>很重要的一点就是作为"前辈"，一定要指导"后辈"，而且是不厌其烦、事无巨细的指导！最好的方法莫过结对了，不过应该是你看着他写，而不是他看着你写。指导对"后辈"当然有意义，对你也有：能减轻自己的负担——他会了你就不用干了，可以腾出时间来做更有意义的事情。这和磨刀不误砍柴工是一个道理。以前我这方面做得就不好，觉得自己会，教别人麻烦，不如自己干了还快。现在想开了，呵呵。</p> <p><br>还有一个很好的办法是施加压力，恰当的时候布置一些不可能完成的学习任务，比如一周读700页C#高编（我就这么干过，当时那个兄弟真的很拼命，呵呵）。这里还要注意方法，遣将不如激将，可以刺激他一下。沟通技巧仍然是最重要的。</p> <p><br>还可以树立典型，比如你可以树立和你合作的那个美工作为典型，一种老大哥的形象，遇到问题就能一个唱白脸一个唱红脸。附加团队激励作用。</p> <p><br>另外自身时刻关注最新技术，保持自身的竞争力和领导力。领导就是要领着大家（倒下的），所以一定要走在前面。</p> <p><br>目前想到的就这么多了，对于管理我也只能算新手，以上这些经验希望对你有用，也希望和你多交流！</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1263162.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41963/" target="_blank">[新闻]《极品飞车12》最新真人照片、游戏截图</a>]]></description></item><item><title>团队职能划分</title><link>http://www.cnblogs.com/yuandong/archive/2008/08/06/Rules_In_Team.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Wed, 06 Aug 2008 01:39:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/08/06/Rules_In_Team.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1261663.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/08/06/Rules_In_Team.html#Feedback</comments><slash:comments>41</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1261663.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1261663.html</trackback:ping><description><![CDATA[<p>以下主要是对中小型团队成员职责的划分，视团队大小可由一人负责兼任多个角色，极端情况下一个人全部搞定！</p> <p><strong>项目经理<br></strong>老大，对项目负责，对领导负责。主要工作有三个：第一是沟通，第二是沟通，第三还是沟通。</p> <p><strong>需求分析（领域专家）</strong><br>项目经理的左辅。翻译器，见人（客户）说人话，见鬼（程序员-.-）说鬼话。</p> <p><strong>架构师</strong><br>项目经理的右弼。服务人员，提供构架这一高级服务，服务于需求，也服务于程序员。好的构架不仅能满足系统的而要求，更重要的是让程序员能很容易的明白，好实现才好修改。</p> <p><strong>程序员<br></strong>人肉代码生成器。</p> <p><strong>美工</strong><br>让系统“看”起来更好一点。高级美工又称前台设计或UI设计，作用是让系统“用”起来更好一点。</p><p><b>测试</b><br>时刻幻想着自己就是“变态”的客户。<br> </p><p><strong>系统维护</strong><br>需要对各类工具软件和服务器软件具有令人发指的敏锐直觉。通常是团队技术革命的引爆点。</p> <p><strong>后勤</strong><br>“三个人肉代码生成器 + 一个合格的后勤 = 三个超级人肉代码生成器”。负责端茶倒水洗衣叠被的专职后勤是能让程序员写程序写的嗷嗷叫的终极激励。强烈建议优先配置。</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1261663.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41962/" target="_blank">[新闻]IBM正在开发超强性能4TB固态硬盘阵列</a>]]></description></item><item><title>战略与战术--再论软件设计的度</title><link>http://www.cnblogs.com/yuandong/archive/2008/08/04/strategy_and_tactics_in_sofware_develop.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Mon, 04 Aug 2008 02:33:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/08/04/strategy_and_tactics_in_sofware_develop.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1259687.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/08/04/strategy_and_tactics_in_sofware_develop.html#Feedback</comments><slash:comments>15</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1259687.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1259687.html</trackback:ping><description><![CDATA[<p>软件开发的时候总是面临着各种决策，大到模块的划分，小到函数体的写法，这些都是设计的问题。做设计不难，难的是做一个好的设计。然而什么是好的设计？标准是什么？</p> <p>军事上常说“战术是为战略服务的”。这句话换到软件上来可以变成很多说法：函数是为对象服务的；对象是为底层设计服务的；底层设计是为构架服务的；构架是为需求服务的；需求是为了客户的生产生活服务的……不同的抽象层次上对应不同的战略与战术。</p> <p><font color="#ff0000">做好一个设计的根本就在于不仅仅着眼于当前的工作层面，而应该能够很好的理解当前工作服务的那个层面！</font></p> <p>比如写函数体吧，就需要理解该函数在当前对象上下文中所处的地位和作用，不理解当然也能完成工作，但却称不上一个“好”字。也许有人会问“什么是好？我把当前函数优化到常数复杂度算是好了吧？”那也未必，“好”与“不好”需要放到大局中去看，如果当前函数只在系统启动的时候调用一次，那就没有优化的意义，尽快完成该函数才叫做“好”！</p> <p>在需求分析方面这一点更重要、更明显！“需求总在变”这话一点儿不假，但是不变的是用户开发这个软件的目的，这才是用户的真正需求。想办法满足用户这个目的就是做好当前项目的捷径。比如现在大部分的中小企业、特别是事业单位的门户或者部门网站，提需求的时候吹得天花乱坠，什么在线办公、客户管理、内部互动啦，说得很好听，其实做了都不用，老板（领导）在意的就俩字：美工！客户的真正目的是什么？政绩！</p> <p>因此，只有战术在战略层面的地位和意义，才能恰如其分的完成手头工作。把每件事情都做到精益求精的不是工程师，是艺术家。就好比憋足了吃奶、如厕、行房的劲打赢每一场丈的指挥官不一定合格，且不说伤亡巨大、天怒人怨，如果连本来应该败掉的诱敌之战也赢了，那就地军法处置！</p> <p>对于.NET企业级应用，涉及的层次理论，可以这么粗略的划分：</p> <p>电子电路 — 汇编 — 系统内核 — CLR — 函数 — 对象 — 设计模式 — 架构 — 需求 — 客户的生产力（竞争力）</p> <p>搞.NET的大部分工作在函数、对象、设计模式这个层面上，构架师当然是工作在构架的层面、需求分析师以需求为主。敏捷软件开发提倡的一点就是软件的目的在于提升客户（在它们那个领域）的竞争力，这明确的提出软件工程中一个更高级别的抽象层次。剩下的通常不属于咱们操心的范围了。</p> <p>写函数的时候看看对象；看对象的时候关注一下模式；搞模式的时候瞅瞅构架；做构架的时候不能忘了需求。这不但是职业规划，更是做好当前工作的必要条件，难怪人家说：不想当将军的士兵不是好士兵！</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1259687.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41961/" target="_blank">[新闻]Microsoft F# CTP(2008年9月)</a>]]></description></item><item><title>渠道的力量</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/28/Channel_Is_Powerful.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Sat, 28 Jun 2008 13:22:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/28/Channel_Is_Powerful.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1231788.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/28/Channel_Is_Powerful.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1231788.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1231788.html</trackback:ping><description><![CDATA[<p>这两天iPhone的消息一浪高过一浪，乔老爷的策略不可以说不惊人，$199的定价让iPhone狠狠的扎进了千千万万果粉和准果粉的心，<a href="http://www.cnbeta.com/articles/58656.htm">程序员跟风而上</a>，<a href="http://www.cnbeta.com/articles/55219.htm">天朝山寨伺机而动</a>，一时间iPhone声名鹊起，传遍神州大地。</p> <p>不久，就有人开始揭露了<a href="http://www.maoxinyu.cn/steve-jobs-wwdc.html">乔布斯的阳谋</a>。分析硬件多少钱，协议多少钱，捆绑多少钱，分析乔老爷疯狂地利润和跨时代的手机战略，似乎手机市场顷刻间就要翻天覆地。</p> <p>乔布斯的商业目光确实独到，他不把手机做成硬件也不做成软件，而是做成了最能赚钱的——渠道！</p> <p>iPhone或许不能算是严格意义上的手机了，借助iTunes Store，卖音乐、卖电影、卖软件才是苹果的最大利润源。这个模式在iPod上已经证实可行，并且给苹果带来了数亿美元的美妙利润，现在iPhone只是把它推广到了一个更高的层次、更多的领域。<a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/a1930d2ac339_D194/%E6%B8%A0%E9%81%93%E7%9A%84%E5%8A%9B%E9%87%8F_2.jpg"><img style="border: 0px none ; margin: 0px 0px 0px 20px;" alt="渠道的力量" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/a1930d2ac339_D194/%E6%B8%A0%E9%81%93%E7%9A%84%E5%8A%9B%E9%87%8F_thumb.jpg" align="right" border="0" height="330" width="315"></a></p> <p>渠道的力量之所以强大，是因为它掌握了市场。苹果借助卓越的工业设计，笼络了大批的忠实用户，牢牢把握了高端市场的很大份额，而且可以预见，随着苹果市场策略的调整，硬件的大幅度降价，其市场份额有希望在短时间内再上一个台阶。当苹果真正掌握了用户之后，就可以利用渠道的垄断性，向上游的内容提供厂商索取高额的分成利润。也难怪苹果连SDK都敢收费了。</p> <p>做渠道当然不是乔布斯首创的，各行各业都有渠道，这些渠道也都不辱使命，每分每秒都在为其所有者创造巨额的利润。零售业的渠道造就了全球500强之首的沃尔玛；家电行业的渠道孕育了三联、国美和苏宁；掌握世界上最大信息渠道的是Google；致力于二手交易渠道的有ebay、淘宝……。而苹果的高明之处更在于不是争夺已有的渠道，而是把手机做成一个渠道，构建一个前所未有的销售模式。</p> <p>渠道的妙用不仅限于高额的垄断利润，还有“资金流”、“信息流”这些输出。资金流就不用说了，控制的得当，完全是无息贷款。信息流比较新，但是在将来的用途或许更大。比较典型的信息流是Google的Trends和百度的行业报告，沃尔玛也有相应的数据挖掘系统，通过对大量销售信息的统计分析，可以有效的组织货源和营销策略，实现利润最大化。</p> <p>也许手机真的会在iPhone的带领下，成为一个新的渠道，但新生的渠道肯定不会仅次一家。实际上，随着社会分工的不断细化，信息交互和物流的不断发展，愈来愈多的行业会诞生渠道。假设有一天，餐饮市场形成了一个独立的渠道，每天数亿人通过这个渠道吃饭、订餐、了解最新的美食，那这个渠道将会是很大的力量和多厚的利润呢？</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1231788.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41960/" target="_blank">[新闻]微软4.86亿美元收购Greenfield</a>]]></description></item><item><title>再论结对编程</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/25/Something_About_Pair_Programming_Again.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Wed, 25 Jun 2008 12:13:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/25/Something_About_Pair_Programming_Again.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1229898.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/25/Something_About_Pair_Programming_Again.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1229898.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1229898.html</trackback:ping><description><![CDATA[<p>上午刚写了<a href="http://www.cnblogs.com/yuandong/archive/2008/06/25/Pair_Programming_Practice.html">《践行结对编程》</a>，下午就看到<a href="http://www.javaeye.com/">JavaEye</a>上<a href="http://emarket.javaeye.com/">emarket</a>写的<a href="http://emarket.javaeye.com/blog/207558">《XP的反省-Pair Programming》</a>，他认为“pair programming给我带来的的忧大于喜，缺点大于有点”。其中提到Pair表现出高生产力是在实验条件下得出的，而实验的条件是：</p> <ol> <li>Pair的人必须对等 （同班同学）。</li> <li>Pair的人必须全力以赴 (同学们，老师在做实验哦，不要走神！)。</li> <li>Pair的人必须对要解决的问题有相同（或相近）的认知 。</li></ol> <p>其实这和我在<a href="http://www.cnblogs.com/yuandong/archive/2008/06/25/Pair_Programming_Practice.html">《践行结对编程》</a>总结的属于同一个观点；</p> <ol> <li>Pair的人必须对等：水平较低的人容易产生依赖心理，所以需要鼓励水平低的人主动，而水平高的应该以指导和沟通为主。</li> <li>Pair的人必须全力以赴：结对其实本来会使人全力以赴，两人一起做事情的时候，没有走神儿的条件。</li> <li>Pair的人必须对要解决的问题有相同（或相近）的认知：结对的两个人对结对的任务都必须实现有了解做到心中有数。而结对时也要经过讨论，达成共识，然后方能动手写程序。</li></ol> <p>“pair on everything则是对人性的强奸”，这话有点儿过了，估计是作者的公司实施的问题，这点从他们“老板的原则是绝不让任何一个知识点停留在一个人的脑瓜里”，可以看出一点。pair on everything是不太合适的，这点儿<a href="http://www.crisp.se/henrik.kniberg">Henrik Kniberg</a>在<a href="http://www.infoq.com/minibooks/scrum-xp-from-the-trenches">《Scrum and XP from the Trenches》</a>中也有提到。我们团队在操作的时候也曾经要求pair on everything，后来成员有意见，慢慢的变更了方案。但是pair on programm还是有好处的，这点儿也是我们团队实践后得出的共同结论。</p> <p>说到底，结对只是一种方法，没有对不对，只有合适不合适。以前用瀑布模式的时候也有人骂，现在敏捷有人骂，没有什么好奇怪的。其实是这些方法不适合或者实施的时候没有抓住精髓，而是形式化了。</p> <p>管理是一门艺术，软件工程也是。为什么满大街都是讲管理的书，而因为管理不好倒闭的公司仍然满大街都是？因为不适合、因为不变通，所以纵然有再好的软件工程学方法，还是会有失败的项目。</p> <p>一直认为<strong>管理和设计一样，没有好坏，无非“取舍”二字</strong>。就像高中有道经典的物理学题目：子弹打木块。可以用速度解、可以用能量解，大学学了微积分之后还可以用微积分解，没有哪一种解法好那一种不好，只是合不合适的问题。</p> <p>所以要学习各种解法、了解他们的优点缺点和适用范围，不同的情景采用不同的方法，甚至混合使用多种方法。</p> <p>不过，最重要的还是——理解问题的本质！</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1229898.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41959/" target="_blank">[新闻]苹果已然取代微软地位成行业众矢之的</a>]]></description></item><item><title>践行结对编程</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/25/Pair_Programming_Practice.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Wed, 25 Jun 2008 01:59:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/25/Pair_Programming_Practice.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1229375.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/25/Pair_Programming_Practice.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1229375.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1229375.html</trackback:ping><description><![CDATA[<p>我们团队从五一之后开始实行结对编程，至今两个月了，取得了明显效果的同时，也遇到很多问题。</p> <p><strong>先说说优点。</strong></p> <ol> <li>学习和上手的速度快<br>我们团队除了我之外有四个人，开始的时候其中只有一个勉强算是了解需求和系统结构的，还有一个新成员连.Net都没用过。实行结对之后，几乎没有使用额外的培训时间，一周之后就基本上可以参与到工作中了，无论是业务需求、系统构架、版本控制、内部API，用得到的地方基本上都掌握了。事后总结，之所以学的快的原因，一是用到的才去学，目的明确，学着有劲；二是有人带着，手把手的演示，比自己看书摸索快多了；三是边学边用，掌握的扎实。</li> <li>Bug明显减少、代码质量提高。<br>第一阶段（我一个人完成的）：24个Bug；第二阶段（四人结对）：12个Bug。考虑到我已经写了三年多的程序，而他们四个都才开始学不到一年（有一个还不到一个月），这个Bug率应该是非常让人满意的。另外在代码格式上，更工整和统一，毕竟是两个人写出来的。</li> <li>团队凝聚力增强<br>这就是个感觉，成员之间亲近了不少。</li></ol> <p><strong>再说说遇到的问题。</strong></p> <p>主要出在两个人之间的配合上，有的时候会有依赖心理，特别是两个人水平有差距、或者其中一个人对今天的工作不太了解的时候。还有的时候不适合结对，比如对一个新的技术点进行尝试和攻关的时候。</p> <p><strong>关于变更结对伙伴。</strong></p> <p>我们开始的时候实行每半天一换，后来发现思路切换的太过频繁，延长到一天一换。不过仍然发现思路中断是很难受的事情。所以现在不以时间为单位了，改成一个任务一换。</p> <p><strong>我们现在使用的结对方式。</strong></p> <ol> <li>结对以任务为单位，完成一个任务后变更结对伙伴。  </li><li>结对前，每个人对要进行的任务独立思考，形成一个解决方案。  </li><li>结对时，两人拿出各自的方案进行讨论，达成一致后，编写代码。  </li><li>结对时，水平较低的应该主动积极，水平较高的应该以沟通和指导为主。  </li><li>任务完成后，应及时总结，特别是对任务涉及系统模块进一步了解。</li></ol><img src ="http://www.cnblogs.com/yuandong/aggbug/1229375.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41959/" target="_blank">[新闻]苹果已然取代微软地位成行业众矢之的</a>]]></description></item><item><title>网络爬虫（2）：存储</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/24/Web_Spider_Store.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Tue, 24 Jun 2008 08:17:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/24/Web_Spider_Store.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1229048.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/24/Web_Spider_Store.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1229048.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1229048.html</trackback:ping><description><![CDATA[   <p>目前我想到的存储方案有两种：单文件单页面存储和单文件多页面存储。</p> <p>单文件单页面存储就是一个页面存储在一个文件中，文件名称可以使用页面编号doc_id。这种方案查找的时候容易定位，直接使用文件名就可以，缺点是会产生大量琐碎的文件，管理、冗余和查询感觉都不太方便。</p> <p>单文件多页面存储即一个文件存储多个页面，写满一个文件后，自动开始写下一个。每个文件有一个编号store_file_id，在查找某一个页面的时候，通过页面的编号doc_id，可以找到对应的store_file_id及页面在文件中的位置position，然后就能找个这个页面。每个文件的大小是可以定制的，默认200M一个。一个页面的数据不会分在两个文件中，只会在一个页面写入完成后，才会发生写新文件的操作，所以存储实际的大小会是200M多几十K。</p> <p>目前采用的就是单文件多页面的存储方式。其中的每个页面又按以下格式存放数据：</p> <ol> <li>doc_id：页面文档编号，unsigned int，该页面的url的md5签名。  </li><li>timestamp：页面的抓取时间，time_t类型。  </li><li>is_analyzed：该页面是否已经分析，bool（short）类型。  </li><li>url_length：该页面url的长度，unsigned int。  </li><li>url：该页面的url，长度为url_length的char数组。  </li><li>domain_length：域名的长度，unsigned int，类似url_length。  </li><li>domain：域名，长度为domain_length的char数组，类似url。  </li><li>response_length：响应的长度，unsigned int，类似url_length。  </li><li>response：响应的内容，长度为response_length的char数组，类似url。</li></ol> <p>存储格式图示如下（单一存储文件）：</p> <p><a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/2_D0A4/%E9%A1%B5%E9%9D%A2%E5%AD%98%E5%82%A8_2.jpg"><img style="border: 0px none ;" alt="页面存储" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/2_D0A4/%E9%A1%B5%E9%9D%A2%E5%AD%98%E5%82%A8_thumb.jpg" border="0" height="153" width="763"></a> </p> <p>store模块中的主要函数如下：</p><pre class="csharpcode"><span class="rem">/*</span>
<span class="rem"> * 初始化文件存储，在调用store_page方法前，必须先调用此方法。</span>
<span class="rem"> *     @store_path               存储路径</span>
<span class="rem"> *     @store_file_max_length    存储文件的最大长度，单位是字节</span>
<span class="rem"> */</span>
<span class="kwrd">extern</span> <span class="kwrd">int</span> initial_store(<span class="kwrd">char</span>* store_path, unsigned <span class="kwrd">long</span> store_file_max_length);
<span class="rem">/*</span>
<span class="rem"> * 关闭文件存储</span>
<span class="rem"> */</span>
<span class="kwrd">extern</span> <span class="kwrd">int</span> close_store();
<span class="rem">/*</span>
<span class="rem"> * 将页面存储到磁盘</span>
<span class="rem"> *     @page    要储存的页面</span>
<span class="rem"> */</span>
<span class="kwrd">extern</span> <span class="kwrd">int</span> store_page(page* page);
<span class="rem">/*</span>
<span class="rem"> * 取得下一个未分析的页面</span>
<span class="rem"> *     @page   用于存在数据的页面</span>
<span class="rem"> *     @return 成功返回0，出错返回－1，没有未分析的页面，返回1</span>
<span class="rem"> */</span>
<span class="kwrd">extern</span> <span class="kwrd">int</span> get_page_to_parse(page* page);</pre>
<p>initial_store和close_store这对方法用于开始和结束。initial_store会根据给出的store_path自动计算出下一个要写入的文件的编号和位置。close_store负责关闭文件指针，这两个函数在主程序中出现，且只出现一次：initial_store在出程序的开始，close_store在主程序的结束。</p>
<p>store_page和get_page_to_parse这对方法用于写入和读出。store_page将给出的page结构体写入文件，同时负责新存储文件的创建等。get_page_to_parse则负责读取下一个要分析的页面，存储在page指针中。get_page_to_parse还会将这次读取给出的文件在磁盘中标记为已分析。</p>
<p>这里的分析的含义仅指提取页面中的url。</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1229048.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41958/" target="_blank">[新闻]Intel 收购 Poky Linux ,为 MID 注入新的动力</a>]]></description></item><item><title>多走一步</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/24/One_More_Step.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Tue, 24 Jun 2008 00:56:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/24/One_More_Step.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1228617.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/24/One_More_Step.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1228617.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1228617.html</trackback:ping><description><![CDATA[<p>看了<a href="http://home.wangjianshuo.com/">王建硕</a>的<a href="http://home.wangjianshuo.com/cn/20060907_aecaeec.htm">《世界不是天才创造的》</a>，里面的游戏很有意思，也很有启发性。在软件开发中，其实也存在这样的现象，即：比规则前进了一步，不多不少，刚刚好一步，方能取得成功。</p> <p>比如说需求分析，今天下午和客户谈需求时，客户提要求说：“文章分类分成两级，第一级包含XXX、第二级包含XXXX”。这个时候，我们多走一步，按无限级分类系统的要求设计，当用户提出要“第二级下面再分第三级”（这种可能性相当高）的时候，我们就可以开心的笑了。再比如说，客户提“校内分配的比率不能低于60%”，我们当然知道这里的60%是会变的，所以多走一步，将其作为一个可以由用户修改的设置值，就不怕哪天用说要改70%的时候，我们还要重新编译部署了。类似这样的例子还有很多，而有经验的分析人员其实早就是这么做的。</p> <p>设计的时候也是这个样子，很多人（包括我）都在强调：不要做过度设计，哪么怎么把握设计的度？还是多走一步。比如系统要支持Access和SQL，那就用抽象的数据访问层好了。</p> <p>多走一步，不多也不少，如果我们在设计完抽象数据层之后，还要预防时候Oracle的情况，再设计一个Oracle的Provider，就走的有点儿远了。</p> <p>这“一步”有多大，还看具体的情况，我的看法是：团队的水平越高、步伐越小；水平越低、步伐越大。因为水平高了，写出来的代码质量高，容易改，在发生变化时，能很好的适应；水平低的，写出来的代码通常比较僵硬，改起来的成本高，不如开始的时候考虑的多一点儿。</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1228617.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41958/" target="_blank">[新闻]Intel 收购 Poky Linux ,为 MID 注入新的动力</a>]]></description></item><item><title>网络爬虫（1）：概述</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/20/Web_Spider_Summary.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Fri, 20 Jun 2008 01:56:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/20/Web_Spider_Summary.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1226375.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/20/Web_Spider_Summary.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1226375.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1226375.html</trackback:ping><description><![CDATA[<p>最近开始写搜索引擎项目了，基于Linux平台的，用纯C编写。项目主要参考以下书籍：</p> <ol> <li>《走进搜索引擎》，梁斌，电子工业出版社  <li>《搜索引擎原理、实践与应用》，卢亮、张博文，电子工业出版社  <li>《搜索引擎——原理、技术与系统》，李晓明、闫宏非、王继民，科学出版社</li></ol> <p>这三本书其实重复的部分很多，但是国内这方面的参考资料实在少的可怜，而且太偏理论，所以有条件的话，还是建议把三本书都找来读读。</p> <p><strong>开发计划</strong></p> <p>项目第一步是实现对于给定范围内的数据的抓取和更新，目标区域是海大所有网站或教育网所有网站，千万级的数据量。</p> <p>这个计划又分为三步：</p> <ol> <li>单线程定向抓取  <li>多线程抓取  <li>分布式抓取</li></ol> <p>目前第一步：单线程的定向抓取已经完成。</p> <p><strong>流程</strong></p> <p>整个系统的流程图如下：</p> <p><a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/1_86F7/%E6%8A%93%E5%8F%96%E6%B5%81%E7%A8%8B_2.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="750" alt="抓取流程" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/1_86F7/%E6%8A%93%E5%8F%96%E6%B5%81%E7%A8%8B_thumb.jpg" width="568" border="0"></a> </p> <p><strong>系统模块</strong></p> <p>根据系统的流程将其分为七个模块：</p> <ol> <li>store：负责数据的存储，包括将页面储存到磁盘、获取下一个未分析的页面等。  <li>url_info：负责Url信息的转换，主要是根据Url提取域名和服务器的IP地址。  <li>url_index：判断Url是否已被抓取。  <li>url_filter：Url过滤器，用于实现定向抓取。  <li>http：负责根据Url抓取页面。  <li>page_parse：页面的解析，提取包含的Url。  <li>main：主程序。</li></ol> <p>以后会陆续介绍各个模块的实现。</p> <p><strong>开发环境</strong></p> <p>操作系统：Ubuntu 8.04</p> <p>部署服务器：Ubuntu 8.04 Server</p> <p>编译工具：gcc，make</p> <p>IDE：Eclipse CDT 4.0.1</p> <p>版本控制：Subversion</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1226375.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41957/" target="_blank">[新闻]雅虎将关闭社交网站Mash</a>]]></description></item><item><title>沟通、务实、平等——读《Scrum and XP from the Trenches》</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/19/Read_Scrum_and_XP_from_the_Trenches.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Thu, 19 Jun 2008 02:10:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/19/Read_Scrum_and_XP_from_the_Trenches.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1225217.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/19/Read_Scrum_and_XP_from_the_Trenches.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1225217.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1225217.html</trackback:ping><description><![CDATA[<p>昨天读完了<a href="http://www.infoq.com/minibooks/scrum-xp-from-the-trenches">《Scrum and XP from the Trenches》</a>这本书（小册子），说的是敏捷开发的实践，作者<a href="http://www.crisp.se/henrik.kniberg">Henrik Kniberg</a>写的很有幽默，读起来颇有些欲罢不能的感觉。</p>
<p>敏捷的开发方法一直给我一种“聪明人的游戏”的感觉，这伙人似乎都有一个共同的特点：很能扯。换种说法，应该是很强的沟通能力吧！这应该和敏捷开发的价值观有关。</p>
<p><strong>沟通</strong></p>
<p>敏捷中的沟通，包括客户与团队的沟通、团队与团队的沟通、团队内部的沟通。敏捷方法认为这些沟通应该是日常的、每天甚至每时都在进行的事情，是每个人的事情而不是某一个人的事情。比如“客户作为团队成员”，就是旨在将客户与团队的沟通视为日常工作。</p>
<p>加强沟通的最好办法就是降低沟通的成本。就我们团队实践敏捷的经验来看，其实成员之间是很想沟通的，前提是沟通起来很容易：如果A坐在你的旁边，相信你很乐意和他讨论，如果找B必须打总机、转分机、再找人喊他一声，估计你会很快打消和他聊聊的念头。所以，敏捷团队通常要求成员“在一起”，即便是不能物理上在一起，也要通过视频、语音、IM等手段，让他们看起来貌似在一起。不过还是要想方设法的让成员真正的坐在一起，毕竟我们是在工作，对吗？</p>
<p>“结对编程”就要求很强的沟通能力，或许这倒是招人的好办法：你的简历上不是说团队协作能力强吗？结对试试吧！</p>
<p><strong>务实</strong></p>
<p>敏捷一直强调的是能用的代码，强调尽快的将系统交付给客户，通过代码而不是文档和用户沟通，让人感觉很踏实。从用户的角度来看，总能看到真金白银、可以实际操作的系统；从开发人员的角度来看，一步一步向终点迈进，信心十足。其实这和现在Web公司的思想有些类似，以前做网站都是大，任何网站都想把自己做成门户，现在不了，改成瞄准一个领域，先争取上线运行再说，一点点的发展。</p>
<p>务实的另一个要点是不做任何多余的东西。TDD最能表现这一特点——绝不写任何多余的代码，绝不做任何过度的设计。“用户故事”也是这么一种思路，让用户描述应用场景，而不是通过用户描述想法，猜用户需要什么。而且用户没有明确提出来的东西绝对不考虑。即便是用户明确提出来了，还要分个优先级出来，首要实现最重要的。</p>
<p>务实应该重内容而不重形式，比如<a href="http://www.crisp.se/henrik.kniberg">Henrik Kniberg</a>对于“总结”有个说法：The most important thing about retrospectives is to make sure they happen。关键在于你做了，而且想办法把它做好，至于怎么做最好，就要视情况而定了。</p>
<p><strong>平等</strong></p>
<p>团队的成员是平等的，无论是在技术上还是职责上，任何人都了解项目的任何部分，并且被鼓励发表意见。代码是共有的，所有人都有权修改。知识在团队内部快速传播，使得每个人都有完成项目任何部分的能力。</p>
<p>这似乎不太符合咱们的国情，比如“团队所有人都有权修改代码”，在领导（中国特色的职务）看来，太危险了，谁都能改还不乱了套？但是<a href="http://www.crisp.se/henrik.kniberg">Henrik Kniberg</a>说，这种方法很有效，我们团队的实践也证明了这一点，其实，一个团队的伙伴，谁会乱来？</p>
<p>&nbsp;</p>
<p>敏捷的方法或许只能用在软件开发中，但敏捷的的思想却不仅限软件工程，在“一切都是项目”的今天，做什么工作不能敏捷一点？</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1225217.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41956/" target="_blank">[新闻]中国互联网战争局势图</a>]]></description></item><item><title>谁决定谁？谁依赖谁？谁拥有谁？</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/13/1219369.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Fri, 13 Jun 2008 07:58:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/13/1219369.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1219369.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/13/1219369.html#Feedback</comments><slash:comments>33</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1219369.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1219369.html</trackback:ping><description><![CDATA[摘要: 系统模块之间的关系&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/06/13/1219369.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1219369.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41955/" target="_blank">[新闻]开源多点触摸技术试运行</a>]]></description></item><item><title>微型项目实践（12）：查询与显示</title><link>http://www.cnblogs.com/yuandong/archive/2008/06/04/1213908.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Wed, 04 Jun 2008 12:51:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/06/04/1213908.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1213908.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/06/04/1213908.html#Feedback</comments><slash:comments>6</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1213908.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1213908.html</trackback:ping><description><![CDATA[   <p>上一篇中，我们分析了页面中的控件和数据绑定中的扩展方法，今天我们看数据的查询和显示。其中，数据的查询属于业务逻辑层（Business），而显示属于UI层。</p> <p>假设我们要根据以下两个条件进行查询：</p> <ol> <li>日志分类（ID）  </li><li>发布时间（范围）</li></ol> <p>两者为“AND”的关系，则查询可以通过通过扩展IQueryable&lt;Blog&gt;类实现，该功能定义在BlogExtension类中（位于DongBlog.Business\Blogs\Blog.cs文件中），代码如下：</p> <div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">   2:  </span><span class="rem">/// 根据日志分类取得日志</span></pre><pre><span class="lnum">   3:  </span><span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">   4:  </span><span class="rem">/// &lt;param name="query"&gt;日志查询&lt;/param&gt;</span></pre><pre><span class="lnum">   5:  </span><span class="rem">/// &lt;param name="blogClassID"&gt;日志分类ID&lt;/param&gt;</span></pre><pre><span class="lnum">   6:  </span><span class="rem">/// &lt;param name="createDataTimeStart"&gt;日志发表的起始时间&lt;/param&gt;</span></pre><pre><span class="lnum">   7:  </span><span class="rem">/// &lt;param name="createDataTimeEnd"&gt;日志发表的结束时间&lt;/param&gt;</span></pre><pre><span class="lnum">   8:  </span><span class="rem">/// &lt;returns&gt;该分类下的日志&lt;/returns&gt;</span></pre><pre><span class="lnum">   9:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> List&lt;Blog&gt; GetBlogsBy(<span class="kwrd">this</span> IQueryable&lt;Blog&gt; query, </pre><pre>          <span class="kwrd">int</span>? blogClassID, DateTime? createDataTimeStart, DateTime? createDataTimeEnd)</pre><pre><span class="lnum">  10:  </span>{</pre><pre><span class="lnum">  11:  </span>    <span class="kwrd">if</span> (query == <span class="kwrd">null</span>)</pre><pre><span class="lnum">  12:  </span>        <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentNullException(<span class="str">"query"</span>);</pre><pre><span class="lnum">  13:  </span>&nbsp;</pre><pre><span class="lnum">  14:  </span>    var q = query.AsQueryable();</pre><pre><span class="lnum">  15:  </span>&nbsp;</pre><pre><span class="lnum">  16:  </span>    <span class="kwrd">if</span> (blogClassID.HasValue)</pre><pre><span class="lnum">  17:  </span>        q = q.Where(b =&gt; b.BlogClassID == blogClassID.Value);</pre><pre><span class="lnum">  18:  </span>    <span class="kwrd">if</span> (createDataTimeStart.HasValue)</pre><pre><span class="lnum">  19:  </span>        q = q.Where(b =&gt; b.CreateDateTime &gt; createDataTimeStart.Value);</pre><pre><span class="lnum">  20:  </span>    <span class="kwrd">if</span> (createDataTimeEnd.HasValue)</pre><pre><span class="lnum">  21:  </span>        q = q.Where(b =&gt; b.CreateDateTime &lt; createDataTimeEnd.Value);</pre><pre><span class="lnum">  22:  </span>&nbsp;</pre><pre><span class="lnum">  23:  </span>    <span class="kwrd">return</span> q</pre><pre><span class="lnum">  24:  </span>        .OrderByDescending(b =&gt; b.CreateDateTime)</pre><pre><span class="lnum">  25:  </span>        .ToList();</pre><pre><span class="lnum">  26:  </span>}</pre></div>
<p>这段代码充分运用了Linq面向对象的方法进行数据库的查询，表间关联使用类的引用表示，最终会由Linq2SQL翻译为SQL语句。这种方法可以完成非常复杂的查询，在我们团队目前的项目中，最多的在一次查询中涉及五个表，几十个字段条件，条件还包括等于，大于、小于、属于，相似等多种情况。</p>
<p>这段代码虽然实现了查询功能，不过存在几个问题：第一，CreateDataTimeStart和CreateDataTimeEnd应该是一个表示范围的整体；第二，函数的参数随着查询条件的增加会变得越来越臃肿；第三，没有考虑分页。我们重构一下以上代码，解决这些问题。</p>
<p>在重构之前，还有一个要注意的是：重构的安全网——测试。在这个系统中，由于规模很小，没有实现完整的测试。但是所有的代码都是可以（并且容易）测试的，比如上面这个查询函数，可以通过实现用于测试的IQueryable&lt;Blog&gt;实现自动化测试。</p>
<p>我们先来重构第一个问题，抽取CreateDataTimeStart和CreateDataTimeEnd作为一个类，称之为TimeRange，放在Common层中，代码如下：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">using</span> ...</pre><pre><span class="lnum">   5:  </span>&nbsp;</pre><pre><span class="lnum">   6:  </span><span class="kwrd">namespace</span> DongBlog.Common</pre><pre><span class="lnum">   7:  </span>{</pre><pre><span class="lnum">   8:  </span>    <span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">   9:  </span>    <span class="rem">/// 表示一个时间段</span></pre><pre><span class="lnum">  10:  </span>    <span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">  11:  </span>    <span class="kwrd">public</span> <span class="kwrd">class</span> TimeRange</pre><pre><span class="lnum">  12:  </span>    {</pre><pre><span class="lnum">  13:  </span>&nbsp;</pre><pre><span class="lnum">  14:  </span>        <span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">  15:  </span>        <span class="rem">/// 取得或设置起始时间</span></pre><pre><span class="lnum">  16:  </span>        <span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">  17:  </span>        <span class="kwrd">public</span> DateTime? StartTime { get; set; }</pre><pre><span class="lnum">  18:  </span>&nbsp;</pre><pre><span class="lnum">  19:  </span>        <span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">  20:  </span>        <span class="rem">/// 取得或设置终止时间</span></pre><pre><span class="lnum">  21:  </span>        <span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">  22:  </span>        <span class="kwrd">public</span> DateTime? EndTime { get; set; }</pre><pre><span class="lnum">  23:  </span>&nbsp;</pre><pre><span class="lnum">  24:  </span>        <span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">  25:  </span>        <span class="rem">/// 构造一个时间段</span></pre><pre><span class="lnum">  26:  </span>        <span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">  27:  </span>        <span class="kwrd">public</span> TimeRange() { }</pre><pre><span class="lnum">  28:  </span>        <span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">  29:  </span>        <span class="rem">/// 构造一个时间段</span></pre><pre><span class="lnum">  30:  </span>        <span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">  31:  </span>        <span class="rem">/// &lt;param name="startTime"&gt;起始时间&lt;/param&gt;</span></pre><pre><span class="lnum">  32:  </span>        <span class="rem">/// &lt;param name="endTime"&gt;终止时间&lt;/param&gt;</span></pre><pre><span class="lnum">  33:  </span>        <span class="kwrd">public</span> TimeRange(DateTime startTime, DateTime endTime)</pre><pre><span class="lnum">  34:  </span>        {</pre><pre><span class="lnum">  35:  </span>            <span class="kwrd">this</span>.StartTime = startTime;</pre><pre><span class="lnum">  36:  </span>            <span class="kwrd">this</span>.EndTime = endTime;</pre><pre><span class="lnum">  37:  </span>        }</pre><pre><span class="lnum">  38:  </span>    }</pre><pre><span class="lnum">  39:  </span>}</pre></div>
<p>然后GetBlogs函数可以重构为：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> List&lt;Blog&gt; GetBlogsBy(</pre><pre>             <span class="kwrd">this</span> IQueryable&lt;Blog&gt; query, <span class="kwrd">int</span>? blogClassID, TimeRange createDateTime)</pre><pre><span class="lnum">   2:  </span>{</pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (query == <span class="kwrd">null</span>)</pre><pre><span class="lnum">   4:  </span>        <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentNullException(<span class="str">"query"</span>);</pre><pre><span class="lnum">   5:  </span>&nbsp;</pre><pre><span class="lnum">   6:  </span>    var q = query.AsQueryable();</pre><pre><span class="lnum">   7:  </span>&nbsp;</pre><pre><span class="lnum">   8:  </span>    <span class="kwrd">if</span> (blogClassID.HasValue)</pre><pre><span class="lnum">   9:  </span>        q = q.Where(b =&gt; b.BlogClassID == blogClassID.Value);</pre><pre><span class="lnum">  10:  </span>&nbsp;</pre><pre><span class="lnum">  11:  </span>    <span class="kwrd">if</span> (createDateTime != <span class="kwrd">null</span>)</pre><pre><span class="lnum">  12:  </span>    {</pre><pre><span class="lnum">  13:  </span>        <span class="kwrd">if</span> (createDateTime.StartTime.HasValue)</pre><pre><span class="lnum">  14:  </span>            q = q.Where(b =&gt; b.CreateDateTime &gt; createDateTime.StartTime.Value);</pre><pre><span class="lnum">  15:  </span>        <span class="kwrd">if</span> (createDateTime.EndTime.HasValue)</pre><pre><span class="lnum">  16:  </span>            q = q.Where(b =&gt; b.CreateDateTime &lt; createDateTime.EndTime.Value);</pre><pre><span class="lnum">  17:  </span>    }</pre><pre><span class="lnum">  18:  </span>&nbsp;</pre><pre><span class="lnum">  19:  </span>    <span class="kwrd">return</span> q</pre><pre><span class="lnum">  20:  </span>        .OrderByDescending(b =&gt; b.CreateDateTime)</pre><pre><span class="lnum">  21:  </span>        .ToList();</pre><pre><span class="lnum">  22:  </span>}</pre></div>
<p>对月第二和第三个问题，我们利用前面提到的Common层的Query相关类一并解决。添加BlogQueryInformation类，代码如下：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">   2:  </span><span class="rem">/// 日志查询信息</span></pre><pre><span class="lnum">   3:  </span><span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">   4:  </span><span class="kwrd">public</span> <span class="kwrd">class</span> BlogQueryInformation : QueryInformation</pre><pre><span class="lnum">   5:  </span>{</pre><pre><span class="lnum">   6:  </span>    <span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">   7:  </span>    <span class="rem">/// 取得或设置日志分类ID</span></pre><pre><span class="lnum">   8:  </span>    <span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">   9:  </span>    <span class="kwrd">public</span> <span class="kwrd">int</span>? BlogClassID { get; set; }</pre><pre><span class="lnum">  10:  </span>    <span class="rem">/// &lt;summary&gt;</span></pre><pre><span class="lnum">  11:  </span>    <span class="rem">/// 取得或设置日志发表时间</span></pre><pre><span class="lnum">  12:  </span>    <span class="rem">/// &lt;/summary&gt;</span></pre><pre><span class="lnum">  13:  </span>    <span class="kwrd">public</span> TimeRange CreateDateTime { get; set; }</pre><pre><span class="lnum">  14:  </span>}</pre></div>
<p>这样，就可以把GetBlogs方法重构如下：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">public</span> <span class="kwrd">static</span> QueryResult&lt;Blog&gt; GetBlogsBy(</pre><pre>           <span class="kwrd">this</span> IQueryable&lt;Blog&gt; query, BlogQueryInformation queryInfo)</pre><pre><span class="lnum">   2:  </span>{</pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (query == <span class="kwrd">null</span>)</pre><pre><span class="lnum">   4:  </span>        <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentNullException(<span class="str">"query"</span>);</pre><pre><span class="lnum">   5:  </span>    <span class="kwrd">if</span> (queryInfo == <span class="kwrd">null</span>)</pre><pre><span class="lnum">   6:  </span>        <span class="kwrd">throw</span> <span class="kwrd">new</span> ArgumentNullException(<span class="str">"queryInfo"</span>);</pre><pre><span class="lnum">   7:  </span>&nbsp;</pre><pre><span class="lnum">   8:  </span>    var q = query.AsQueryable();</pre><pre><span class="lnum">   9:  </span>&nbsp;</pre><pre><span class="lnum">  10:  </span>    <span class="kwrd">if</span> (queryInfo.BlogClassID.HasValue)</pre><pre><span class="lnum">  11:  </span>        q = q.Where(b =&gt; b.BlogClassID == queryInfo.BlogClassID.Value);</pre><pre><span class="lnum">  12:  </span>&nbsp;</pre><pre><span class="lnum">  13:  </span>    <span class="kwrd">if</span> (queryInfo.CreateDateTime != <span class="kwrd">null</span>)</pre><pre><span class="lnum">  14:  </span>    {</pre><pre><span class="lnum">  15:  </span>        <span class="kwrd">if</span> (queryInfo.CreateDateTime.StartTime.HasValue)</pre><pre><span class="lnum">  16:  </span>            q = q.Where(b =&gt; b.CreateDateTime &gt; queryInfo.CreateDateTime.StartTime.Value);</pre><pre><span class="lnum">  17:  </span>        <span class="kwrd">if</span> (queryInfo.CreateDateTime.EndTime.HasValue)</pre><pre><span class="lnum">  18:  </span>            q = q.Where(b =&gt; b.CreateDateTime &lt; queryInfo.CreateDateTime.EndTime.Value);</pre><pre><span class="lnum">  19:  </span>    }</pre><pre><span class="lnum">  20:  </span>&nbsp;</pre><pre><span class="lnum">  21:  </span>    var resultList = q.OrderByDescending(b =&gt; b.CreateDateTime)</pre><pre><span class="lnum">  22:  </span>        .Skip(queryInfo.Begin).Take(queryInfo.Limit)</pre><pre><span class="lnum">  23:  </span>        .ToList();</pre><pre><span class="lnum">  24:  </span>&nbsp;</pre><pre><span class="lnum">  25:  </span>    <span class="kwrd">return</span> <span class="kwrd">new</span> QueryResult&lt;Blog&gt;(resultList, q.Count());</pre><pre><span class="lnum">  26:  </span>}</pre></div>
<p>最后两句代码实现了分页功能。以后添加新的查询条件时，只需要修改BlogQueryInformation和GetBlogs方法就可以了，函数的签名不需要修改。</p>
<p>然后我们看页面的调用，Default页面中，负责显示的代码如下：</p>
<div class="csharpcode"><pre><span class="lnum">   1:  </span><span class="kwrd">protected</span> <span class="kwrd">void</span> Page_Load(<span class="kwrd">object</span> sender, EventArgs e)</pre><pre><span class="lnum">   2:  </span>{</pre><pre><span class="lnum">   3:  </span>    <span class="kwrd">if</span> (!IsPostBack)</pre><pre><span class="lnum">   4:  </span>        display();</pre><pre><span class="lnum">   5:  </span>}</pre><pre><span class="lnum">   6:  </span>&nbsp;</pre><pre><span class="lnum">   7:  </span><span class="kwrd">private</span> <span class="kwrd">void</span> display()</pre><pre><span class="lnum">   8:  </span>{</pre><pre><span class="lnum">   9:  </span>    var pageCountHelper = <span class="kwrd">new</span> PageCountHelper(<span class="kwrd">this</span>, <span class="str">"篇"</span>);</pre><pre><span class="lnum">  10:  </span>    var queryInfo = <span class="kwrd">new</span> BlogQueryInformation();</pre><pre><span class="lnum">  11:  </span>&nbsp;</pre><pre><span class="lnum">  12:  </span>    queryInfo.BlogClassID = getBlogClassID();</pre><pre><span class="lnum">  13:  </span>    queryInfo.CreateDateTime = getCreateDateTime();</pre><pre><span class="lnum">  14:  </span>    queryInfo.Begin = pageCountHelper.CurrentPageCount</pre><pre>                 * pageCountHelper.RecordPerPage;</pre><pre><span class="lnum">  15:  </span>    queryInfo.Limit = pageCountHelper.RecordPerPage;</pre><pre><span class="lnum">  16:  </span>&nbsp;</pre><pre><span class="lnum">  17:  </span>    var result = Database.Blogs.GetBlogsBy(queryInfo);</pre><pre><span class="lnum">  18:  </span>    ListView_BlogList.DataSource = result.ResultList;</pre><pre><span class="lnum">  19:  </span>    LiteralPageCount.Text = pageCountHelper.GetPageCountHtml(result.Total);</pre><pre><span class="lnum">  20:  </span>&nbsp;</pre><pre><span class="lnum">  21:  </span>    DataBind();</pre><pre><span class="lnum">  22:  </span>}</pre><pre><span class="lnum">  23:  </span><span class="kwrd">private</span> TimeRange getCreateDateTime()</pre><pre><span class="lnum">  24:  </span>{</pre><pre><span class="lnum">  25:  </span>    var createDateTime = <span class="kwrd">new</span> TimeRange();</pre><pre><span class="lnum">  26:  </span>    <span class="kwrd">return</span> TimeRange.TryPrase(Request[<span class="str">"CreateDateTime"</span>], createDateTime) ? </pre><pre>                 createDateTime : <span class="kwrd">null</span>;</pre><pre><span class="lnum">  27:  </span>}</pre><pre><span class="lnum">  28:  </span><span class="kwrd">private</span> <span class="kwrd">int</span>? getBlogClassID()</pre><pre><span class="lnum">  29:  </span>{</pre><pre><span class="lnum">  30:  </span>    var blogClassIDString = Request[<span class="str">"BlogClassID"</span>];</pre><pre><span class="lnum">  31:  </span>    <span class="kwrd">return</span> String.IsNullOrEmpty(blogClassIDString) ? </pre><pre>               <span class="kwrd">null</span> : <span class="kwrd">new</span> Nullable&lt;<span class="kwrd">int</span>&gt;(Convert.ToInt32(blogClassIDString));</pre><pre><span class="lnum">  32:  </span>}</pre></div>
<p>即：构造查询条件 -&gt; 调用业务逻辑层（这里是GetBlogs方法）进行查询 -&gt; 显示查询结果。其中用到了PageCountHelper这个辅助类，负责处理页面的分页，原理很简单，无非是拼Html，细节可以参考代码。</p>
<p>Master页面中，用于显示日志分类的ListView也使用这种方法实现数据绑定。至此，日志显示、根据日志分类的简单筛选和分页都已经实现了，最后我们得到了如下效果：</p>
<p><a href="/images/cnblogs_com/yuandong/WindowsLiveWriter/12_9E19/image_2.png"><img style="border: 0px none ;" alt="image" src="http://www.cnblogs.com/images/cnblogs_com/yuandong/WindowsLiveWriter/12_9E19/image_thumb.png" border="0" height="484" width="604"></a> </p>
<p>其中的测试数据，使用测试（InitialTestData）填充。</p>
<p></p>
<p><a href="/Files/yuandong/20080604DongBlog.rar">代码下载</a></p><img src ="http://www.cnblogs.com/yuandong/aggbug/1213908.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41954/" target="_blank">[新闻]国内软件外包高管集聚大连 探讨竞争与应对策略</a>]]></description></item><item><title>乱弹程序语言</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/28/1209212.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Wed, 28 May 2008 06:19:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/28/1209212.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1209212.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/28/1209212.html#Feedback</comments><slash:comments>36</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1209212.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1209212.html</trackback:ping><description><![CDATA[摘要: 语言，就是程序员手中的刀。&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/28/1209212.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1209212.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41953/" target="_blank">[新闻]Mac OS X 10.5.5 Build 9F23 测试版和 Safari 4 预览版</a>]]></description></item><item><title>微型项目实践（11）：控件与格式化显示</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/27/1208215.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Tue, 27 May 2008 03:02:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/27/1208215.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1208215.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/27/1208215.html#Feedback</comments><slash:comments>28</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1208215.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1208215.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇介绍了页面中的控件及显示数据的格式化技巧。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/27/1208215.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1208215.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41952/" target="_blank">[新闻]十月上市 Google手机HTC Dream官方图现</a>]]></description></item><item><title>微型项目实践（10）：Master &amp; Default</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/26/1207324.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Mon, 26 May 2008 02:09:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/26/1207324.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1207324.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/26/1207324.html#Feedback</comments><slash:comments>29</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1207324.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1207324.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇介绍了页面设计的大体设计和实际项目中页面设计的技巧。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/26/1207324.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1207324.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41951/" target="_blank">[新闻]2008年8月29日IT博客精选</a>]]></description></item><item><title>微型项目实践（9）：页面的数据访问策略</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/17/1201508.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Sat, 17 May 2008 11:59:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/17/1201508.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1201508.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/17/1201508.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1201508.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1201508.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇介绍了如何在页面中使用数据访问层，特别是如何避开Linq的一些误区。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/17/1201508.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1201508.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41950/" target="_blank">[新闻]微软在华布局农村手机 定位小城镇和打工者</a>]]></description></item><item><title>微型项目实践（8）：数据访问的实现</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/12/1193891.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Mon, 12 May 2008 08:38:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/12/1193891.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1193891.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/12/1193891.html#Feedback</comments><slash:comments>12</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1193891.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1193891.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇介绍了数据访问的实现方式。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/12/1193891.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1193891.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41949/" target="_blank">[新闻]暴雪确认《星际争霸2》将不会在08年内发售</a>]]></description></item><item><title>微型项目实践（7）：数据访问的定义</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/10/1191019.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Sat, 10 May 2008 02:47:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/10/1191019.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1191019.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/10/1191019.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1191019.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1191019.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇分析了模块间耦合，并讲述了数据访问的定义。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/10/1191019.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1191019.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41948/" target="_blank">[新闻]福布斯:IE8很多功能针对谷歌 微软要玩偷袭</a>]]></description></item><item><title>微型项目实践（6）：Business层代码分析——实体类的生成策略</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/09/1190563.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Fri, 09 May 2008 12:53:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/09/1190563.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1190563.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/09/1190563.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1190563.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1190563.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇分析了实体类的生成策略和用法。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/09/1190563.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1190563.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41947/" target="_blank">[新闻]施密特：谷歌计划十月份开始推进与雅虎合作</a>]]></description></item><item><title>微型项目实践（5）：Business层代码分析——实体基类</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/08/1188936.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Thu, 08 May 2008 12:52:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/08/1188936.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1188936.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/08/1188936.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1188936.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1188936.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇分析了实体基类的代码及其设计思路。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/08/1188936.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1188936.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41946/" target="_blank">[新闻]微软加快XP专业版反盗版步伐</a>]]></description></item><item><title>微型项目实践（4）：Common层代码分析</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/05/1184125.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Mon, 05 May 2008 14:21:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/05/1184125.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1184125.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/05/1184125.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1184125.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1184125.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇分析了Common层的代码。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/05/1184125.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1184125.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41945/" target="_blank">[新闻]Mozilla与谷歌续签三年搜索合同</a>]]></description></item><item><title>微型项目实践（3）：实体代码的生成</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/04/1182358.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Sun, 04 May 2008 13:46:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/04/1182358.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1182358.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/04/1182358.html#Feedback</comments><slash:comments>13</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1182358.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1182358.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的朋友有些帮助！<br /><br>该篇介绍了业务实体代码的生成和系统的依赖关系。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/04/1182358.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1182358.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41944/" target="_blank">[新闻]CBS推出新版CNET重推视频</a>]]></description></item><item><title>微型项目实践（2）：用测试驱动代码生成</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/03/1180370.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Sat, 03 May 2008 08:20:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/03/1180370.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1180370.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/03/1180370.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1180370.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1180370.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的新手朋友有些帮助！<br /><br>该篇描述了如何使用测试驱动代码的生成和数据库脚本的生成策略。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/03/1180370.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1180370.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41943/" target="_blank">[新闻]轮回－新浪推出Facebook模式的SNS</a>]]></description></item><item><title>微型项目实践（1）：用XML描述实体</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/02/1179790.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Fri, 02 May 2008 12:42:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/02/1179790.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1179790.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/02/1179790.html#Feedback</comments><slash:comments>19</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1179790.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1179790.html</trackback:ping><description><![CDATA[摘要: <p>.Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的新手朋友有些帮助！<br /><br>该篇描述了用XML描述业务实体的方法及其优点。</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/02/1179790.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1179790.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41940/" target="_blank">[新闻]惠普139亿美元完成对EDS的收购</a>]]></description></item><item><title>微型项目实践（系列文章）</title><link>http://www.cnblogs.com/yuandong/archive/2008/05/01/1178913.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Thu, 01 May 2008 13:01:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/05/01/1178913.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1178913.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/05/01/1178913.html#Feedback</comments><slash:comments>8</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1178913.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1178913.html</trackback:ping><description><![CDATA[摘要: <p>Net发展的如此之快：2.0，3.0，3.5……版本的不断升级让人应接不暇；Linq，Ajax.Net，SilverLight……各种新特性更是让眼花缭乱。这些新技术一方面极大的提高了开发效率，另一方面，又给我们提出了严峻的考验：如何能在项目中合理的使用这些新技术，使它们相互配合，发挥出最大功效？<br /><br>本系列将以一个Blog系统的开发为例子，从数据分析开始，一步步讲解一个系统的架构，并在这个过程中介绍以上这些技术的使用方式。另外，文章还将介绍作者在实际项目中积累的一些经验和技巧。麻雀虽小，五脏俱全，希望本文对于哪些不知道该如何组织实际代码的新手朋友有些帮助！</p>&nbsp;&nbsp;<a href='http://www.cnblogs.com/yuandong/archive/2008/05/01/1178913.html'>阅读全文</a><img src ="http://www.cnblogs.com/yuandong/aggbug/1178913.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41939/" target="_blank">[新闻]搜狗五笔输入法发布</a>]]></description></item><item><title>学习的方法</title><link>http://www.cnblogs.com/yuandong/archive/2008/03/05/1092595.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Wed, 05 Mar 2008 13:48:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/03/05/1092595.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1092595.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/03/05/1092595.html#Feedback</comments><slash:comments>51</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1092595.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1092595.html</trackback:ping><description><![CDATA[<p>作为IT业的一员，我们几乎每天都有大量的知识需要学习，有大量的技能等待我们去掌握。几乎从我决定“献身”程序员这一伟大事业之后，我就一直在考虑怎么提高自身的学习的能力（简称学习力），以下两张图作为我多年学习生涯得来的宝贵经验，拿出来和同学们分享。
</p><p align="center"><img src="http://www.cnblogs.com/images/cnblogs_com/yuandong/%E9%87%91%E5%AD%97%E5%A1%94.JPG" alt="金字塔.JPG" border="0" height="200"> <img src="http://www.cnblogs.com/images/cnblogs_com/yuandong/%E5%A4%AA%E6%9E%81%E5%9B%BE.jpg" alt="太极图.jpg" border="0" height="200"></p>
<p>如果你看到的第一张是埃及的金字塔，第二张是中国的太极图，说明我的图片没错：第一张代表“知识的金子塔结构”，第二张说明了“理论和实践的相生相克原理”。</p>
<p>一、知识的金字塔结构。我把我了解的软件知识分成了四个层次：思想，原理，技术和应用，他们之间的关系就像金字塔一样：</p>
<p align="center"><img src="http://www.cnblogs.com/images/cnblogs_com/yuandong/%E7%9F%A5%E8%AF%86%E7%9A%84%E9%87%91%E5%AD%97%E5%A1%94%E7%BB%93%E6%9E%84%E5%89%AF%E6%9C%AC.jpg" alt="知识的金字塔结构副本.jpg" border="0" height="287" width="320">&nbsp;</p>
<ol>
    <li>
    <div align="left">思想：目前我觉得能上思想的就两个：算法和面向对象。</div>
    </li>
    <li>原理：原理就有很多了，比如计算机组成原理，网络连接的原理，操作系统的文件访问原理，GC的运行原理等等。</li>
    <li>技术：这个就数不过来了，比如Asp.net技术啦，Ajax，WPF……这些统统是技术。</li>
    <li>应用：世界上所有机器上运行的代码，都算是应用。</li>
</ol>
<p><font color="#ff0000">思想到应用的划分没有高低贵贱，而只是抽象层次的不同。</font></p>
<p>学习的过程，就是通过某一个应用，了解它所使用的技术，进而掌握其中的原理，最后，领悟其中的思想。这大概也就对应了“了解”、“掌握”和“精通”这三个层次吧。所以<font color="#ff0000">学习力的高低，在于对高层次抽象的掌握能力。</font></p>
<p>举个例子：设计模式这最近几年很火，23个模式翻来覆去的有人在讲。我不知道有几个人认真看了，又有几个人能记得住，反正我比较懒，也比较笨。但是笨人有笨办法，面向对象就那么几个概念：“继承”、“派生”、“多态”，说的再具体一点，也就DIP，SRP这么几个原则，大体看看每个设计模式中运用了哪些概念和什么原则，下次在遇到类似的问题，估计就能把这个模式用出去。（PS：此处选择性的忽略了模式在沟通上的意义，呵呵）。</p>
<p>所以要提高学习力，咱们看书就地多看些有深度的书，什么“精通”啦、“速成”啦，就免了。孙子兵法、道德经之类的思想藏的太深，想用在代码里咱没那水平。像《敏捷软件开发 原则、模式与实践》，《深入浅出设计模式》之类的就刚刚好。</p>
<p>可是也千万别认为思想就比应用更重要，没有应用，要思想、原理、技术作甚？</p>
<p>二、理论和实践的相生相克原理。</p>
<p>说完抽象，再看看理论与实践的关系，老祖宗的太极图很形象的说明了这个问题，再看一下：白色代表理论，黑色代表实践：</p>
<p align="center"><img src="http://www.cnblogs.com/images/cnblogs_com/yuandong/%E5%A4%AA%E6%9E%81%E5%9B%BE.jpg" alt="太极图.jpg" border="0" height="200"></p>
<ol>
    <li>白色走到头，和黑色接触的就更多：实践多了，更容易理解理论。</li>
    <li>黑色走到头，和白色接触的也更多：理论的东西看多了，就可以更好的实践。</li>
    <li>白色走到头，就会产生黑色：实践的东西多了，自然会有理论产生。</li>
    <li>黑色走到头，就会产生白色：理论的东西多了，自然而然就会想去试试看。</li>
</ol>
<p>所以我常用的方法是边看书，边写程序，看完书就试着把学到的东西用在项目里。感觉这样能把知识体系穿起来，容易记，不容易忘；写程序写多了就回过头来琢磨一下看看哪儿好哪儿不好，下次肯定会有进步。</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1092595.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41938/" target="_blank">[新闻]新学年开始 大学生适用的十大互联网应用</a>]]></description></item><item><title>工作狂</title><link>http://www.cnblogs.com/yuandong/archive/2008/03/02/1088086.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Sun, 02 Mar 2008 13:37:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/03/02/1088086.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1088086.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/03/02/1088086.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1088086.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1088086.html</trackback:ping><description><![CDATA[<p>经常有人说我是工作狂，对此，我一直是一笑了之，因为我从来没有认为我是个工作狂，我觉得说我是工作狂的不是在拿我开玩笑，就是不了解我。可是我最近认真的考虑这个问题的时候，却突然发现或许我错了。</p>
<p>什么是工作狂？或者什么样的人才能配的上“工作狂”这一荣誉称号？似乎没有确切的定义。那么就试着分析一下吧。</p>
<p>一，工作时间。正常的工作是一天八个小时，每周五天，也就是40个小时。算一下我，每天从早上八点半到晚上十点半，14个小时，去掉吃饭两个小时，12个小时，中间可能会有休息的时间，但是晚上有时候回去还会再干会儿，所以按照12个小时算。然后，一周工作7天，7*12=84个小时。天！是一般人工作时间的两倍。更可怕的是，我几乎所有的时间，都在工作！好吧，我承认，从这一点来看，我工作的狂了一点。</p>
<p>二，为什么工作。通常不工作就觉得活不下去浑身难受的人，可以算上当之无愧的工作狂了。至于我嘛……我觉得不太一样，我每天工作，只是一个习惯而已，对，习惯。貌似从高一开始就养成了这个习惯，大一的时候，这个习惯进一步得到强化。目前的状态是：一天不工作，就觉得缺少了点什么……貌似也快算的上“狂”了，虽然我觉得“彪”这个字眼更合适。</p>
<p>三，其他的方面。我不知道其他的工作狂会是什么样，我也不觉得我身边的人有谁是工作狂，因为，我觉得整日工作是再正常不过的事情了。不过貌似头疼、眼疼、腰疼、脖子疼这些病，经常出现在我和我认识的人身上。</p>
<p>四，最近又发现了自己一个可怕的事情。我在做工作以外的时候，经常走神：打游戏的时候走神儿，看电影的时候走神儿，甚至……徒手娱乐的时候也走神儿……会想起代码，构架，管理和手头项目的进度计划！天，这太可怕了~~~</p>
<p>好吧，我承认了，我工作狂，终日沉迷于工作……</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1088086.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41937/" target="_blank">[新闻]Google拟在9月发布自有浏览器 或采用火狐内核</a>]]></description></item><item><title>内核的忙碌生活</title><link>http://www.cnblogs.com/yuandong/archive/2008/02/18/1072651.html</link><dc:creator>冬冬</dc:creator><author>冬冬</author><pubDate>Mon, 18 Feb 2008 11:23:00 GMT</pubDate><guid>http://www.cnblogs.com/yuandong/archive/2008/02/18/1072651.html</guid><wfw:comment>http://www.cnblogs.com/yuandong/comments/1072651.html</wfw:comment><comments>http://www.cnblogs.com/yuandong/archive/2008/02/18/1072651.html#Feedback</comments><slash:comments>39</slash:comments><wfw:commentRss>http://www.cnblogs.com/yuandong/comments/commentRss/1072651.html</wfw:commentRss><trackback:ping>http://www.cnblogs.com/yuandong/services/trackbacks/1072651.html</trackback:ping><description><![CDATA[<p>我，作为计算机的内核，也就是人们眼中所谓的操作系统，是不折不扣的幕后英雄！给大家说说都干了些什么，你们就知道我不是在吹牛了。</p>
<p>随着散热风扇的嗡嗡声响起，我的忙碌生活就开始了。BIOS大哥习惯做甩手掌柜，把里里外外扫一遍发现没什么意外后，就通知CPU，省下的事情，照旧——找内核。然后，睡大觉去了。</p>
<p>CPU是我们这儿的顶梁柱，脑子特好使，几乎从来不犯错误。不过这位同志的缺点就是太缺乏主观能动性，总是不断的问我：“下一步干什么？下一步干什么？”，他不觉得烦，我就要不厌其烦的告诉他。</p>
<p>于是我开始捣鼓硬盘：“小样，醒醒，把Shell给我”。硬盘这伙计懒，虽然记性没话说，但就是磨叽，找个东西要半天。对于我这个忙碌习惯了的人来说，实在受不了，所以我都是告诉他该找什么，然后该忙什么忙什么，反正找到了他会通知我（硬件中断）。或者有时候干脆让他和内存自己嘀咕去（DMA）。不过大家在一起时间长了，彼此也就了解了，有些合作的技巧：比如说我经常让他找东西的时候多找点，相关的、用得到的，一股脑给我（预读取），我都放到内存里（磁盘缓存），省得他麻烦，也省的自己老着急。</p>
<p>内存正好和硬盘正相反，反应快是没话说，但一歇班就全忘干净了。于是还要硬盘一点点的告诉他，累。</p>
<p>几位同事都准备好了，就开始干活。其实我是个演员，不对不对，是管理人员，而且只是个中层管理人员。所以上面还有几个老板（内核程序），还要伺候一大堆客户（用户程序）。</p>
<p>老板好说，所有领导的话都是对的（内核总是假定内核的程序没有错误）、都是重要的、紧急的（内核认为内核的要求都是合理的，应该尽快满足的）。所以都应该是尽量满足。客户的情况就复杂了，经常会有客户想干不能干的事情，而且客户还可能会犯错误。这些都要进行协调，能解决的就尽量解决，实在无可救药的，也只能舍小家，为大家了。（杀进程）</p>
<p>不管是老板还是客户，分配的任务也是五花八门：有的要求反应快，比如Shell和文本编辑程序，但是通常任务不重，也就是显示个字，存个盘啥的，我们管这叫交互式进程；也有任务重的，比如编译程序，但是快点慢点都成，这叫批处理进程；还要得要求隔一段时间就想做点儿什么的，比如计划任务啥的，算是实时进程。总之，根据不同的任务特点，也有不同的应对办法。但是这也要花心思，通过任务过去干过什么来确定他的特点，我们内部管这叫“基于过去行为的启发式算法”。</p>
<p>而我要做的事情就是尽可能地满足所有人的要求！为了完成这个impossible mission，我努力学习、不断总结经验教训，掌握了以下办法：</p>
<ol>
    <li>把任务切片。由于CPU同志从来不关心在做什么、也从来不知道下一步要做什么。所以我就让他这个时间段干这个任务，下个时间段干下个任务。这样CPU同志就会分身术了！</li>
    <li>把内存分页。一个字节一个字节分配内存是会累死人的，而我的办法是把把内存分成4K、4K的一小块，然后按块分配。在此基础上，我还会用4K到4M不同大小的段来分配内存，以便解决内存的碎片问题，这就是著名的“伙伴算法”。</li>
    <li>学会偷懒。有很多事情不一定立刻要做，比如说有的任务要求在内存里分配个地方，我的办法是让他觉得“貌似”已经分配完了就可以了，至于真正开辟内存空间，还是等他用到这块空间的时候再说吧，一个小小的缺页异常处理就可以搞定。</li>
    <li>我还会能通过复杂的算法在固定的时间内决定下一个要处理的任务，这对付成百上千的任务时，效果相当好。</li>
    <li>......</li>
</ol>
<p>类似这样的工作技巧太多太多了，哎呀，又一个中断响了，我要去忙了，同志们再见！o(∩_∩)o...</p><img src ="http://www.cnblogs.com/yuandong/aggbug/1072651.html?type=1" width = "1" height = "1" /><br><br><a href="http://news.cnblogs.com/n/41936/" target="_blank">[新闻]微软正在构思将Wi-Fi带入汽车</a>]]></description></item></channel></rss>