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

<channel>
	<title>北风技术专栏 &#187; 张章</title>
	<atom:link href="http://column.ibeifeng.com/wp-feed.php?author_name=zhangzhang&#038;feed=feed" rel="self" type="application/rss+xml" />
	<link>http://column.ibeifeng.com</link>
	<description>用技术点亮生活中每个亮点</description>
	<pubDate>Tue, 07 Apr 2009 09:38:07 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>使用RPM包管理命令的笔记</title>
		<link>http://column.ibeifeng.com/zhangzhang/20081113216.shtml</link>
		<comments>http://column.ibeifeng.com/zhangzhang/20081113216.shtml#comments</comments>
		<pubDate>Thu, 13 Nov 2008 02:36:52 +0000</pubDate>
		<dc:creator>张章</dc:creator>
		
		<category><![CDATA[其他]]></category>

		<category><![CDATA[rpm]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=216</guid>
		<description><![CDATA[安装RPM包
安装的命令如下：
shell&#62; rpm -ivh xxx-version.rpm
-i是安装选项、v是显示安装信息、h是用“#”来显示安装进度。
如果是升级安装就是：
shell&#62; rpm -Uvh xxx-version.rpm
-U是升级选项，其余同上。

还有一些公用的选项：
&#8211;keep-temps 保留安装时用到的临时文件，在/tmp目录下
&#8211;quiet 和vh选项相反，只有在安装出错时才提示信息
查询RPM包
我们在安装之前一般都需要对系统已有的包或需要安装的包本身进行查询，命令如下：
shell&#62; rpm -qa&#124;grep java 查询已安装过的java的包
shell&#62; rpm -qpl java-version.rpm 列出未安装的包中的文件
shell&#62; rpm -qf /usr/bin/java 查询已安装的文件属于什么包
-q是查询选项、a是显示所有已安装包、grep是只显示指定的包、p是未安装的包、l是列出RPM包含的文件、f是根据文件查找宿主包、R是显示包的依赖关系、s是显示包状态、i也是显示包信息同安装选项。
验证RPM包
验证是用RPM包来验证系统已经安装的软件
shell&#62; rpm -V xxx.rpm
-V是验证选项。
删除RPM包
删除RPM包
shell&#62; rpm -e xxx.rpm
-e是删除选项。
通用选项
&#8211;force 强制安装或删除
&#8211;nodeps 在破坏依赖关系的基础上强制执行，不建议使用
&#8211;test 测试执行
原载：姓张那小子
北风技术专栏授权发布，谢绝未经本人书面授权的转载。
]]></description>
			<content:encoded><![CDATA[<p>安装RPM包<br />
安装的命令如下：<br />
shell&gt; rpm -ivh xxx-version.rpm<br />
-i是安装选项、v是显示安装信息、h是用“#”来显示安装进度。</p>
<p>如果是升级安装就是：<br />
shell&gt; rpm -Uvh xxx-version.rpm<br />
-U是升级选项，其余同上。</p>
<p><span id="more-216"></span></p>
<p>还有一些公用的选项：<br />
&#8211;keep-temps 保留安装时用到的临时文件，在/tmp目录下<br />
&#8211;quiet 和vh选项相反，只有在安装出错时才提示信息</p>
<p>查询RPM包<br />
我们在安装之前一般都需要对系统已有的包或需要安装的包本身进行查询，命令如下：<br />
shell&gt; rpm -qa|grep java 查询已安装过的java的包<br />
shell&gt; rpm -qpl java-version.rpm 列出未安装的包中的文件<br />
shell&gt; rpm -qf /usr/bin/java 查询已安装的文件属于什么包<br />
-q是查询选项、a是显示所有已安装包、grep是只显示指定的包、p是未安装的包、l是列出RPM包含的文件、f是根据文件查找宿主包、R是显示包的依赖关系、s是显示包状态、i也是显示包信息同安装选项。</p>
<p>验证RPM包<br />
验证是用RPM包来验证系统已经安装的软件<br />
shell&gt; rpm -V xxx.rpm<br />
-V是验证选项。</p>
<p>删除RPM包<br />
删除RPM包<br />
shell&gt; rpm -e xxx.rpm<br />
-e是删除选项。</p>
<p>通用选项<br />
&#8211;force 强制安装或删除<br />
&#8211;nodeps 在破坏依赖关系的基础上强制执行，不建议使用<br />
&#8211;test 测试执行</p>
<p><em>原载：<a href="http://www.zhangzhang.net/" target="_blank">姓张那小子</a><br />
北风技术专栏授权发布，谢绝未经本人书面授权的转载。</em></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/zhangzhang/20081113216.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>使用Apache mod_evasive防DDOS攻击</title>
		<link>http://column.ibeifeng.com/zhangzhang/20081022201.shtml</link>
		<comments>http://column.ibeifeng.com/zhangzhang/20081022201.shtml#comments</comments>
		<pubDate>Wed, 22 Oct 2008 13:42:42 +0000</pubDate>
		<dc:creator>张章</dc:creator>
		
		<category><![CDATA[数据库]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=201</guid>
		<description><![CDATA[配置mod_evasive模块
mod_evasive的前身就是mod_dosevasive，它可以有效防止DDOS攻击。
首先把mod_evasive下载到 /usr/local/src 下，然后解压缩

shell&#62; cd /usr/local/src
shell&#62; tar -zxvf mod_evasive_1.10.1.tar.gz
shell&#62; cd modsecurity-apache-1.9/apache2/
shell&#62; cp apxs-ciamod_evasive20.c /opt/apache/bin/


在httpd.conf中添加下列一段mod_security的配置文件

LoadModule evasive20_module modules/mod_evasive20.so     
＜ifmodulemod_evasive20 .c＞
DOSHashTableSize3097
DOSPageCount2
DOSSiteCount50
DOSPageInterval1
DOSSiteInterval1
DOSBlockingPeriod10
＜/ifmodulemod_evasive20＞

原载：姓张那小子
北风技术专栏授权发布，谢绝未经本人书面授权的转载。
]]></description>
			<content:encoded><![CDATA[<p>配置mod_evasive模块<br />
mod_evasive的前身就是mod_dosevasive，它可以有效防止DDOS攻击。</p>
<p>首先把mod_evasive下载到 /usr/local/src 下，然后解压缩<br />
<code><br />
shell&gt; cd /usr/local/src<br />
shell&gt; tar -zxvf mod_evasive_1.10.1.tar.gz<br />
shell&gt; cd modsecurity-apache-1.9/apache2/<br />
shell&gt; cp apxs-ciamod_evasive20.c /opt/apache/bin/<br />
</code></p>
<p><span id="more-201"></span></p>
<p>在httpd.conf中添加下列一段mod_security的配置文件<br />
<code><br />
LoadModule evasive20_module modules/mod_evasive20.so     </p>
<p>＜ifmodulemod_evasive20 .c＞<br />
DOSHashTableSize3097<br />
DOSPageCount2<br />
DOSSiteCount50<br />
DOSPageInterval1<br />
DOSSiteInterval1<br />
DOSBlockingPeriod10<br />
＜/ifmodulemod_evasive20＞<br />
</code></p>
<p><em>原载：<a href="http://www.zhangzhang.net/" target="_blank">姓张那小子</a><br />
北风技术专栏授权发布，谢绝未经本人书面授权的转载。</em></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/zhangzhang/20081022201.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>人月神话：编程之道和编程之禅摘录</title>
		<link>http://column.ibeifeng.com/zhangzhang/20081017173.shtml</link>
		<comments>http://column.ibeifeng.com/zhangzhang/20081017173.shtml#comments</comments>
		<pubDate>Fri, 17 Oct 2008 10:47:07 +0000</pubDate>
		<dc:creator>张章</dc:creator>
		
		<category><![CDATA[综合]]></category>

		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=173</guid>
		<description><![CDATA[
对于聪明的人，只要一个字；对于快马，只要轻轻一鞭；对于写得好的程序，只要单独的一个命令。
设计一个千百万程序的操作系统很容易，要改变一个人的本性却困难得多。
开发前面的百分之九十需要一半时间，而另一半时间则用来完成最后的百分之十。
项目计划和公布的时间表，本身毫无意义。那些日期和项目进展的里程碑本质上不意味着什么。然而有一个秘密的时间表，它被所有工作于一个项目的人所理解。这个秘密的时间表从未被外界的关注所愚弄，也从未被操纵以迎合市场的方案。这个秘密的时间表总是被遵守，因为它反映了所有开发部成员之间的相互理解。当项目反映了这个现实时，程序会如期完成；当项目计划与此现实相矛盾时，程序会被延误。   
有三种情况肯定会导致程序设计项目的失败。第一种情况是，主管此项目的经理对软件一无所知；第二种情况是，对程序代码负责的项目带头人对编写代码毫无兴趣；第三种情况是，编写代码的程序员是临时雇佣的，对项目缺乏忠诚。这三种情况中的任何一种都会导致项目的失败；三种情况同时出现，就必死无疑了。
一个程序的价值不能由它的宣传册的大小，或出现在大众计算机杂志上的整页广告的数量来判断。这些噪音越响，程序越不可能有用；真正优秀的程序不需要广告，用户会口口相伟。
一位初学者问大师：“程序设计的真正含义是什么？”
大师回答说：“饿的时侯就吃；困的时侯就睡；当时机恰当时，就进行程序设计。”
一位初学者问大师，“每当我在一套新的系统上编程时，必须学会一种新的语言。为什么没有一套标准呢？”大师转身而去。“唯一真正的标准是死亡。”他说“上个星期我准备劈些木柴烧火，但我的斧子又旧又钝。于是，我去五金店买了把新的。”“这挺有趣儿，”第一位程序员说，“但这和用户界面有什么关系呢？”“这把新斧子附带有一本长达八页的使用说明书。”他回答说。
不懂编程之道的程序员常常把空间和时间消耗殆尽，得道的程序员则总是有足够的空间和时间去完成编程任务。
上士闻道，从而行之。中士闻道，谨而寻之。下士闻道，大笑之。
有一位编程大师，他写非结构化的程序，一位初学者刻意模仿他，也写非结构化的程序。当他让大师看他的进步时，大师批评了他的非结构化程序：“  对一位编程大师合适的东西未必对一个初学者同样合适，在超越结构化之前，你必须理解编程之道。”
一个项目经理带给编程大师一个项目的需求，然后问大师：“如果我给你5个程序员，要多少时间设计这个项目？”“一年”，大师说。“但是我们等不了那么长时间，越快越好，如果10程序员呢？”大师皱了一下眉头说：“那就要花2年”。“那，100年程序员呢？”大师耸了耸肩说：“那这个项目就永远完不成了。”
有人问一位程序员，“一个财务软件和一个操作系统哪个更容易设计？”“是操作系统”，这位程序员回答说。此人大惑不解。他说：“显然一个财务软件比起操作系统来说其复杂性是微不足道的”。程序员说：“不，设计财务软件时，一个程序员必须成为持不同意见的用户与计算机的一个中介，他必须了解用户的操作习惯，报表要是什么形式，如何遵循税法。相反，一个操作系统完全与这些外部的东西无关。设计操作系统，程序员只需要达到自己的设想与机器之间的简单的和谐。这就是为什么操作系统反而比财务软件更容易设计。”这些人笑着说。“不错，但是哪一个更容易调试呢？”程序员没有回答。写的好的程序是它自己的天堂，写的不好的程序是它自己的地狱。
“技巧？”，大师转过身说，“我所遵循的是道–它超乎所有的技巧。当我开始编程时我看到的是整个一大块的程序，三年后我看到的是子过程。现在我什么也看不到了。我的整个存在是没有任何形式的虚无。我感觉很悠闲，总之，事实上是我的程序自己在写，有时我看到一些问题，我看到它们，就停下来静静地观察它们，然后我改变了一行代码，难题就象一阵轻烟一样化为乌有。然后我编译程序。坐在那里享受工作的喜悦。闭了一会眼睛然后退出系统。

一个好的农民不会不管他的庄稼。
一个好的老师不会不管哪怕是最差的学生。
一个好的父亲不会让他的任何一个孩子挨饿。
一个好的程序员不应拒绝维护他的程序。


为什么程序员没有效率，因为他们把时间都浪费在开会上了。
为什么程序员难于管理？因为管理者的干预太多了。
为什么程序员一个接一个地辞职，因为他们累坏了。
在糟糕的管理下工作，他们享受不到工作的乐趣。

经理对程序员说，“你们的工作时间是早上9点到正午点。”，所有的程序员都很不满。经理又说：“好吧，那随你们的便，只要能按时完成任务。”，程序员们这下满意了，他们中午上班，一直工作到凌晨。

]]></description>
			<content:encoded><![CDATA[<ol>
<li>对于聪明的人，只要一个字；对于快马，只要轻轻一鞭；对于写得好的程序，只要单独的一个命令。</li>
<li>设计一个千百万程序的操作系统很容易，要改变一个人的本性却困难得多。</li>
<li>开发前面的百分之九十需要一半时间，而另一半时间则用来完成最后的百分之十。</li>
<li>项目计划和公布的时间表，本身毫无意义。那些日期和项目进展的里程碑本质上不意味着什么。然而有一个秘密的时间表，它被所有工作于一个项目的人所理解。这个秘密的时间表从未被外界的关注所愚弄，也从未被操纵以迎合市场的方案。这个秘密的时间表总是被遵守，因为它反映了所有开发部成员之间的相互理解。当项目反映了这个现实时，程序会如期完成；当项目计划与此现实相矛盾时，程序会被延误。   <span id="more-173"></span></li>
<li>有三种情况肯定会导致程序设计项目的失败。第一种情况是，主管此项目的经理对软件一无所知；第二种情况是，对程序代码负责的项目带头人对编写代码毫无兴趣；第三种情况是，编写代码的程序员是临时雇佣的，对项目缺乏忠诚。这三种情况中的任何一种都会导致项目的失败；三种情况同时出现，就必死无疑了。</li>
<li>一个程序的价值不能由它的宣传册的大小，或出现在大众计算机杂志上的整页广告的数量来判断。这些噪音越响，程序越不可能有用；真正优秀的程序不需要广告，用户会口口相伟。</li>
<li>一位初学者问大师：“程序设计的真正含义是什么？”<br />
大师回答说：“饿的时侯就吃；困的时侯就睡；当时机恰当时，就进行程序设计。”</li>
<li>一位初学者问大师，“每当我在一套新的系统上编程时，必须学会一种新的语言。为什么没有一套标准呢？”大师转身而去。“唯一真正的标准是死亡。”他说“上个星期我准备劈些木柴烧火，但我的斧子又旧又钝。于是，我去五金店买了把新的。”“这挺有趣儿，”第一位程序员说，“但这和用户界面有什么关系呢？”“这把新斧子附带有一本长达八页的使用说明书。”他回答说。</li>
<li>不懂编程之道的程序员常常把空间和时间消耗殆尽，得道的程序员则总是有足够的空间和时间去完成编程任务。</li>
<li>上士闻道，从而行之。中士闻道，谨而寻之。下士闻道，大笑之。</li>
<li>有一位编程大师，他写非结构化的程序，一位初学者刻意模仿他，也写非结构化的程序。当他让大师看他的进步时，大师批评了他的非结构化程序：“  对一位编程大师合适的东西未必对一个初学者同样合适，在超越结构化之前，你必须理解编程之道。”</li>
<li>一个项目经理带给编程大师一个项目的需求，然后问大师：“如果我给你5个程序员，要多少时间设计这个项目？”“一年”，大师说。“但是我们等不了那么长时间，越快越好，如果10程序员呢？”大师皱了一下眉头说：“那就要花2年”。“那，100年程序员呢？”大师耸了耸肩说：“那这个项目就永远完不成了。”</li>
<li>有人问一位程序员，“一个财务软件和一个操作系统哪个更容易设计？”“是操作系统”，这位程序员回答说。此人大惑不解。他说：“显然一个财务软件比起操作系统来说其复杂性是微不足道的”。程序员说：“不，设计财务软件时，一个程序员必须成为持不同意见的用户与计算机的一个中介，他必须了解用户的操作习惯，报表要是什么形式，如何遵循税法。相反，一个操作系统完全与这些外部的东西无关。设计操作系统，程序员只需要达到自己的设想与机器之间的简单的和谐。这就是为什么操作系统反而比财务软件更容易设计。”这些人笑着说。“不错，但是哪一个更容易调试呢？”程序员没有回答。写的好的程序是它自己的天堂，写的不好的程序是它自己的地狱。</li>
<li>“技巧？”，大师转过身说，“我所遵循的是道–它超乎所有的技巧。当我开始编程时我看到的是整个一大块的程序，三年后我看到的是子过程。现在我什么也看不到了。我的整个存在是没有任何形式的虚无。我感觉很悠闲，总之，事实上是我的程序自己在写，有时我看到一些问题，我看到它们，就停下来静静地观察它们，然后我改变了一行代码，难题就象一阵轻烟一样化为乌有。然后我编译程序。坐在那里享受工作的喜悦。闭了一会眼睛然后退出系统。</li>
<li>
<pre>一个好的农民不会不管他的庄稼。
一个好的老师不会不管哪怕是最差的学生。
一个好的父亲不会让他的任何一个孩子挨饿。
一个好的程序员不应拒绝维护他的程序。</pre>
</li>
<li>
<pre>为什么程序员没有效率，因为他们把时间都浪费在开会上了。
为什么程序员难于管理？因为管理者的干预太多了。
为什么程序员一个接一个地辞职，因为他们累坏了。
在糟糕的管理下工作，他们享受不到工作的乐趣。</pre>
</li>
<li>经理对程序员说，“你们的工作时间是早上9点到正午点。”，所有的程序员都很不满。经理又说：“好吧，那随你们的便，只要能按时完成任务。”，程序员们这下满意了，他们中午上班，一直工作到凌晨。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/zhangzhang/20081017173.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>每日构建 Daily build</title>
		<link>http://column.ibeifeng.com/zhangzhang/20081015151.shtml</link>
		<comments>http://column.ibeifeng.com/zhangzhang/20081015151.shtml#comments</comments>
		<pubDate>Wed, 15 Oct 2008 04:16:45 +0000</pubDate>
		<dc:creator>张章</dc:creator>
		
		<category><![CDATA[综合]]></category>

		<category><![CDATA[构建]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=151</guid>
		<description><![CDATA[一个好的办法是每日构建（daily builds）。  每日构建意味着自动地，每天，完整地构建整个代码树、（译者按：“代码树”，原文为source  tree，意思是将整个项目源代码的目录，子目录，文件的位置尽可能事先固定下来，这样在开发过程中各个模块间，各个文件间的相对位置都不会混乱。源代码树指的就是一个项目所有的已经组织好的代码文件。通常代码树应该用版本控制软件管理起来。虽然这个概念很基本，但是据我的观察，国内还是有软件公司在这方面做的不够好的，所以有必要解释一下。）

自动地 － 因为你设定代码每天在固定的时间构建。在Unix环境下使用cron，在windows下使用“任务计划”。
每天 － 或者更频繁. 当然每天构建的次数越多越好啦。但是有时候构建次数还是有上限的，原因和版本控制有关系，等会儿我会谈到的。
完整地 －很可能你的代码有多个版本。多语言版本，多操作系统版本，或者高端低端版本。每日构建（daily  build）需要构建所有这些版本。并且每个文件都需要从头编译，而不是使用编译器的不完美的增量编译功能。
以下是每日构建（daily build）能带来的好处：

当一个bug被修正了，测试者可以很快得到最新的修正后的版本开始重新测试，以验证bug是否真正地被修复了。
开发人员可以更加确定他们对代码做的修改不会破坏1024个操作系统上的任何一个版本。验证这一点不需要在他们的机器上安装OS/2（IBM公司生产的PC机操作系统）。
那些每天将修改过的代码导入（check  in）版本控制服务器的开发人员知道，他们对一个模块导入的修改不会拖别的开发人员的后腿。拖后腿的意思是，那些开发别的模块的程序员使用这个修改过的模块，出了问题，于是他们自己的模块也没有办法开发下去了。每日构建则不会有人拖后腿。如果把一个开发团队比作一台PC机，那么团队中的一个程序员对某个模块的修改导致其他人无法开发别的模块，相当于PC机发生了蓝屏。当一个程序员忘记把他（她）新建立的文件导入到repository（指版本控制服务器上的代码树）时，这种开发过程中的“蓝屏”会经常发生。因为在这个程序员自己的计算机上有这个文件，所以他（她）构建  这个程序没有问题。但是其他程序员是从版本控制服务器上导出（check out）代码的，由于服务器上没有这个文件，他们遇到了链接错误（link  error），无法继续工作了。
外部团队（例如市场销售部门，进行beta测试的一些客户）可以获得一个比较稳定的版本，这样对他们开展自己的工作比较有利。
假如你将每日构建出的二进制文件（例如一个可执行程序，一个dll等等）存档管理，那么当你发现一个非常奇怪的，无法解决的bug时，你可以通过对这些文件进行二进制搜索（binary  search）来确定什么时候这个bug第一次出现。如果有对代码进行了完善的版本控制，你也可以找出是谁在何时对代码进行的导入（check in）导致了这个bug。
当开发者修正了测试者报告的一个错误时，如果测试者同时报告了发现错误时的构建的版本，开发人员可以直接在那个版本中测试是否bug真正被修复了。（译者按：测试者报告出现了一个bug，只是报告了一个错误症状，而错误的原因可能有多个，每个原因可能在不同的模块中。前文中的方法是为了避免只修正了一个模块中一个原因，别的模块由于在变动，于是掩盖了而不是修复了bug）

以下是如何进行每日构建（daily  build）的具体步骤。你需要用最快的电脑建立一个每日构建服务器。写一个脚本，可以自动从版本控制服务器中导出（check  out）完整的代码，（你当然使用版本控制，不是吗？），然后对代码从头开始进行构建（build），要构建所有的版本。如果你有一个安装打包程序，也要在脚本中自动运行。所有会卖给最终用户的东西都要包括在构建过程中。把构建出来的版本放在各自的的目录里，不同时间构建的相同版本也应该按日期整理好，不要相互覆盖。每天固定的时间运行这样的脚本。

最关键的是所有这些步骤都应该由脚本自动化完成，从导出（check  out）代码到将最终产品放在网上供用户下载（当然在开发阶段，产品是放在一台测试服务器上的）。要保证开发过程中的任何东西的任何记录是由文档记录的而不是由某个人的脑子来记录的，这是唯一的办法。否则你会碰到这样的情况，产品需要发布了，可是只有Shaniqua知道如何将产品打包的，可是他刚刚被巴士撞了。在Juno公司（本文作者工作过的公司之一），要进行每日构建，你唯一需要学会的东西就是双击每日构建服务器桌面上的一个快捷方式。
如果你在发行程序的当天发现了一个小bug，没有问题。修正它，然后重新运行每日构建脚本，现在你可以安安心心的发行程序了。当然，黄金定律是每日构建脚本应该是把所有的事情从头做一遍，遵循这个定律就不会有什么问题。
将你的编译器的警告参数设到最大（在微软的VC中是-W4 ; 在GCC中是-Wall），当遇到任何一个最微小的警告时就应该停下来。
如果每日构建失败了，可能整个开发团队的工作会因此进行不下去。当务之急是立刻找出原因，使得每日构建能成功进行下去。某天也许你会一天运行好几次每日构建脚本的。
每日构建一旦失败，应该自动地将失败用email通知整个团队。提取错误日志中的恰当部分并包括在email正文中也不是很难。每日构建脚本也可以将当前的状态报告整理成一个html文件，自动发布到一个所有人都可以访问的web服务器上，这样测试者可以很快知道那个版本的构建是成功的。
当我在微软的excel团队中工作时，我们的一个有效办法是，谁导致每日构建（daily  build）失败，他（她）就得负责照看当日的每日构建（译者按：微软通常每日构建都在半夜），直到有另一个人导致构建失败而接替他（她）。这样做当然可以使每个开发者都小心不要因为自己代码的错误破坏了构建，更重要的是团队中的每个人都可以学会每日构建（daily  build）的原理。
如果你的团队在同一个时区工作，在午饭时间进行每日构建（daily build）是个不错的主意。午饭前每个程序员导入（check  in）代码，这样当程序员在吃饭时，构建系统在工作。当程序员吃完饭回来时，如果每日构建失败了，所有的人也都在，可以尽快找出失败的原因。当构建系统运作起来时，没有人再会担心别人导入（check  in）代码会妨碍自己的工作了。.
如果你的团队同时在两个时区工作，计划好每日构建（daily  build）的时间使得一个时区的工作不会影响另一个时区的工作。在Juno公司，纽约程序员在晚上7：00导入（check  in）到版本控制服务器。如果他们的导入导致构建失败，印度Hyderabad市（译者按：印度科技重镇）的程序员在纽约时间晚上8：00以后的工作几乎无法进行下去。我们每天进行两次每日构建（daily  build），每次构建的时间都在两地的程序员回家之前，这下就没有问题了。

原载：姓张那小子
北风技术专栏授权发布，谢绝未经本人书面授权的转载。
]]></description>
			<content:encoded><![CDATA[<p>一个好的办法是<em>每日构建（daily builds）</em>。  每日构建意味着<em>自动地，每天，完整地</em>构建整个代码树、（译者按：“代码树”，原文为source  tree，意思是将整个项目源代码的目录，子目录，文件的位置尽可能事先固定下来，这样在开发过程中各个模块间，各个文件间的相对位置都不会混乱。源代码树指的就是一个项目所有的已经组织好的代码文件。通常代码树应该用版本控制软件管理起来。虽然这个概念很基本，但是据我的观察，国内还是有软件公司在这方面做的不够好的，所以有必要解释一下。）</p>
<p><span id="more-151"></span></p>
<p><strong>自动地 <em>－</em></strong> 因为你设定代码每天在固定的时间构建。在Unix环境下使用cron，在windows下使用“任务计划”。</p>
<p><strong>每天 －</strong> 或者更频繁. 当然每天构建的次数越多越好啦。但是有时候构建次数还是有上限的，原因和版本控制有关系，等会儿我会谈到的。</p>
<p><strong>完整地 －</strong>很可能你的代码有多个版本。多语言版本，多操作系统版本，或者高端低端版本。每日构建（daily  build）需要构建<em>所有</em>这些版本。并且每个文件都需要从头编译，而不是使用编译器的不完美的增量编译功能。</p>
<p>以下是每日构建（daily build）能带来的好处：</p>
<ol>
<li>当一个bug被修正了，测试者可以很快得到最新的修正后的版本开始重新测试，以验证bug是否真正地被修复了。</li>
<li>开发人员可以更加确定他们对代码做的修改不会破坏1024个操作系统上的任何一个版本。验证这一点不需要在他们的机器上<em>安装</em>OS/2（IBM公司生产的PC机操作系统）。</li>
<li>那些每天将修改过的代码导入（check  in）版本控制服务器的开发人员知道，他们对一个模块导入的修改不会拖别的开发人员的后腿。拖后腿的意思是，那些开发别的模块的程序员使用这个修改过的模块，出了问题，于是他们自己的模块也没有办法开发下去了。每日构建则<em>不会</em>有人拖后腿。如果把一个开发团队比作一台PC机，那么团队中的一个程序员对某个模块的修改导致其他人无法开发别的模块，相当于PC机发生了蓝屏。当一个程序员忘记把他（她）新建立的文件导入到repository（指版本控制服务器上的代码树）时，这种开发过程中的“蓝屏”会经常发生。因为在这个程序员<em>自己的</em>计算机上有这个文件，所以他（她）构建  这个程序没有问题。但是其他程序员是从版本控制服务器上导出（check out）代码的，由于服务器上没有这个文件，他们遇到了链接错误（link  error），无法继续工作了。</li>
<li>外部团队（例如市场销售部门，进行beta测试的一些客户）可以获得一个比较稳定的版本，这样对他们开展自己的工作比较有利。</li>
<li>假如你将每日构建出的二进制文件（例如一个可执行程序，一个dll等等）存档管理，那么当你发现一个非常奇怪的，无法解决的bug时，你可以通过对这些文件进行二进制搜索（binary  search）来确定什么时候这个bug第一次出现。如果有对代码进行了完善的版本控制，你也可以找出是谁在何时对代码进行的导入（check in）导致了这个bug。</li>
<li>当开发者修正了测试者报告的一个错误时，如果测试者同时报告了发现错误时的构建的版本，开发人员可以直接在那个版本中测试是否bug<em>真正</em>被修复了。（译者按：测试者报告出现了一个bug，只是报告了一个错误症状，而错误的原因可能有多个，每个原因可能在不同的模块中。前文中的方法是为了避免只修正了一个模块中一个原因，别的模块由于在变动，于是掩盖了而不是修复了bug）</li>
</ol>
<p>以下是如何进行每日构建（daily  build）的具体步骤。你需要用最快的电脑建立一个每日构建服务器。写一个脚本，可以自动从版本控制服务器中导出（check  out）完整的代码，（你<em>当然使用</em>版本控制，不是吗？），然后对代码从头开始进行构建（build），要构建所有的版本。如果你有一个安装打包程序，也要在脚本中自动运行。所有会卖给最终用户的东西都要包括在构建过程中。把构建出来的版本放在各自的的目录里，不同时间构建的相同版本也应该按日期整理好，不要相互覆盖。每天固定的时间运行这样的脚本。</p>
<ol>
<li>最关键的是<em>所有这些步骤</em>都应该由脚本自动化完成，从导出（check  out）代码到将最终产品放在网上供用户下载（当然在开发阶段，产品是放在一台测试服务器上的）。要保证开发过程中的<em>任何东西</em>的任何记录是由文档记录的而不是由某个人的脑子来记录的，这是唯一的办法。否则你会碰到这样的情况，产品需要发布了，可是只有Shaniqua知道如何将产品打包的，可是他刚刚被巴士撞了。在Juno公司（本文作者工作过的公司之一），要进行每日构建，你唯一需要学会的东西就是双击每日构建服务器桌面上的一个快捷方式。</li>
<li>如果你在发行程序的当天发现了<em>一个小bug</em>，没有问题。修正它，然后重新运行每日构建脚本，现在你可以安安心心的发行程序了。当然，黄金定律是每日构建脚本应该是把所有的事情从头做一遍，遵循这个定律就不会有什么问题。</li>
<li>将你的编译器的警告参数设到最大（在微软的VC中是-W4 ; 在GCC中是-Wall），当遇到任何一个最微小的警告时就应该停下来。</li>
<li>如果每日构建失败了，可能整个开发团队的工作会因此进行不下去。当务之急是立刻找出原因，使得每日构建能成功进行下去。某天也许你会一天运行好几次每日构建脚本的。</li>
<li>每日构建一旦失败，应该自动地将失败用email通知整个团队。提取错误日志中的恰当部分并包括在email正文中也不是很难。每日构建脚本也可以将当前的状态报告整理成一个html文件，自动发布到一个所有人都可以访问的web服务器上，这样测试者可以很快知道那个版本的构建是成功的。</li>
<li>当我在微软的excel团队中工作时，我们的一个有效办法是，谁导致每日构建（daily  build）失败，他（她）就得负责照看当日的每日构建（译者按：微软通常每日构建都在半夜），直到有另一个人导致构建失败而接替他（她）。这样做当然可以使每个开发者都小心不要因为自己代码的错误破坏了构建，更重要的是团队中的每个人都可以学会每日构建（daily  build）的原理。</li>
<li>如果你的团队在同一个时区工作，在午饭时间进行每日构建（daily build）是个不错的主意。午饭前每个程序员导入（check  in）代码，这样当程序员在吃饭时，构建系统在工作。当程序员吃完饭回来时，如果每日构建失败了，所有的人也都在，可以尽快找出失败的原因。当构建系统运作起来时，没有人再会担心别人导入（check  in）代码会妨碍自己的工作了。.</li>
<li>如果你的团队同时在两个时区工作，计划好每日构建（daily  build）的时间使得一个时区的工作不会影响另一个时区的工作。在Juno公司，纽约程序员在晚上7：00导入（check  in）到版本控制服务器。如果他们的导入导致构建失败，印度Hyderabad市（译者按：印度科技重镇）的程序员在纽约时间晚上8：00以后的工作几乎无法进行下去。我们每天进行两次每日构建（daily  build），每次构建的时间都在两地的程序员回家之前，这下就没有问题了。</li>
</ol>
<p><em>原载：<a href="http://www.zhangzhang.net/" target="_blank">姓张那小子</a><br />
北风技术专栏授权发布，谢绝未经本人书面授权的转载。</em></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/zhangzhang/20081015151.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>Apache上使用mod_rewrite防止盗用图片链接</title>
		<link>http://column.ibeifeng.com/zhangzhang/20081015148.shtml</link>
		<comments>http://column.ibeifeng.com/zhangzhang/20081015148.shtml#comments</comments>
		<pubDate>Wed, 15 Oct 2008 04:06:24 +0000</pubDate>
		<dc:creator>张章</dc:creator>
		
		<category><![CDATA[数据库]]></category>

		<category><![CDATA[Apache]]></category>

		<category><![CDATA[防盗链]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=148</guid>
		<description><![CDATA[因为我已经安装了mod_rewrite模块，所以现在全靠它了。设置apache配置文件httpd.conf。

＜directory /＞
Options FollowSymLinks
AllowOverride All 将None修改为All
去掉#ServerName前的#设置为www.zz.net
ServerName www.zz.net:80
设置虚拟主机
NameVirtualHost *
＜virtualhost *＞
DocumentRoot /var/www/html/img.zz.net
ServerName img.zz.net
＜/virtualhost＞


重启Apache2服务，然后修改.htaccess 文件，如果没有就在/var/www/html/img.zz.net新建一个

RewriteEngine on
RewriteCond %{HTTP_REFERER} !
^http://www.zz.net/.*$ [NC]
只允许通过www.zz.net/*才能访问img.zz.net下的文件。
RewriteCond %{HTTP_REFERER} !^http://www.zz.net$ [NC] 
只允许通过www.zz.net才能访问img.zz.net下的文件
RewriteRule .*.(jpg&#124;jpeg&#124;gif&#124;png&#124;bmp&#124;rar&#124;zip&#124;doc)
$ http://error.zz.net/error.cwj[R,NC]
如果非法链接将会转向到错误页面

这样别人就不能用你的图片啦
原载：姓张那小子
北风技术专栏授权发布，谢绝未经本人书面授权的转载。
]]></description>
			<content:encoded><![CDATA[<p>因为我已经安装了mod_rewrite模块，所以现在全靠它了。设置apache配置文件httpd.conf。</p>
<p><code><br />
＜directory /＞<br />
Options FollowSymLinks<br />
AllowOverride All 将None修改为All</p>
<p>去掉#ServerName前的#设置为www.zz.net<br />
ServerName www.zz.net:80<br />
设置虚拟主机<br />
NameVirtualHost *<br />
＜virtualhost *＞<br />
DocumentRoot /var/www/html/img.zz.net<br />
ServerName img.zz.net<br />
＜/virtualhost＞<br />
</code></p>
<p><span id="more-148"></span></p>
<p>重启Apache2服务，然后修改.htaccess 文件，如果没有就在/var/www/html/img.zz.net新建一个</p>
<p><code><br />
RewriteEngine on<br />
RewriteCond %{HTTP_REFERER} !<br />
^http://www.zz.net/.*$ [NC]<br />
只允许通过www.zz.net/*才能访问img.zz.net下的文件。<br />
RewriteCond %{HTTP_REFERER} !^http://www.zz.net$ [NC] </p>
<p>只允许通过www.zz.net才能访问img.zz.net下的文件<br />
RewriteRule .*.(jpg|jpeg|gif|png|bmp|rar|zip|doc)<br />
$ http://error.zz.net/error.cwj[R,NC]<br />
如果非法链接将会转向到错误页面<br />
</code></p>
<p>这样别人就不能用你的图片啦</p>
<p><em>原载：<a href="http://www.zhangzhang.net/" target="_blank">姓张那小子</a><br />
北风技术专栏授权发布，谢绝未经本人书面授权的转载。</em></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/zhangzhang/20081015148.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>SQL优化笔记</title>
		<link>http://column.ibeifeng.com/zhangzhang/20081014117.shtml</link>
		<comments>http://column.ibeifeng.com/zhangzhang/20081014117.shtml#comments</comments>
		<pubDate>Tue, 14 Oct 2008 04:30:53 +0000</pubDate>
		<dc:creator>张章</dc:creator>
		
		<category><![CDATA[数据库]]></category>

		<category><![CDATA[sql]]></category>

		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=117</guid>
		<description><![CDATA[1．索引的使用：
(1).当插入的数据为数据表中的记录数量的10%以上，首先需要删除该表的索引来提高数据的插入效率，当数据插入后，再建立索引。
(2).避免在索引列上使用函数或计算，在where子句中，如果索引是函数的一部分，优化器将不再使用索引而使用全表扫描。如：
 低效：select * from dept where sal*12 &#62;2500;
高效：select * from dept where sal&#62;2500/12;
(3).避免在索引列上使用not和“!=”，索引只能告诉什么存在于表中，而不能告诉什么不存在于表中，当数据库遇到not 和“!=”时，就会停止使用索引而去执行全表扫描。
(4).索引列上&#62;=代替&#62;
低效：select * from emp where deptno &#62; 3
高效：select * from emp where deptno &#62;=4
两者的区别在于，前者dbms将直接跳到第一个deptno等于4的记录，而后者将首先定位到deptno等于3的记录并且向前扫描到第一个deptno大于3的。
(5).非要对一个使用函数的列启用索引，基于函数的索引是一个较好的方案。
2. 游标的使用：
当在海量的数据表中进行数据的删除、更新、插入操作时，用游标处理的效率是最慢的，但是游标又是必不可少的，所以正确使用游标十分重要：
(1). 在数据抽取的源表中使用时间戳，这样每天的维表数据维护只针对更新日期为最新时间的数据来进行，大大减少需要维护的数据记录数。
(2). 在insert和update维表时都加上一个条件来过滤维表中已经存在的记录，例如：
insert into dim_customer select * from ods_customer where ods_customer.code not exists (dim_customer.code)
ods_customer为数据源表。dim_customer为维表。
(3). 使用显式的游标，因为隐式的游标将会执行两次操作，第一次检索记录，第二次检查too many rows这个exception,而显式游标不执行第二次操作。
3． 据抽取和上载时的sql优化：
(1). Where 子句中的连接顺序：
oracle采用自下而上的顺序解析where子句，根据这个原理，表之间的连接必须写在其他where条件之前，那些可以过滤掉大量记录的条件必须写在where子句的末尾。如：
低效：select * from emp e where sal&#62;5000 and job [...]]]></description>
			<content:encoded><![CDATA[<p>1．索引的使用：<br />
(1).当插入的数据为数据表中的记录数量的10%以上，首先需要删除该表的索引来提高数据的插入效率，当数据插入后，再建立索引。<br />
(2).避免在索引列上使用函数或计算，在where子句中，如果索引是函数的一部分，优化器将不再使用索引而使用全表扫描。如：<br />
<span id="more-117"></span> 低效：select * from dept where sal*12 &gt;2500;<br />
高效：select * from dept where sal&gt;2500/12;<br />
(3).避免在索引列上使用not和“!=”，索引只能告诉什么存在于表中，而不能告诉什么不存在于表中，当数据库遇到not 和“!=”时，就会停止使用索引而去执行全表扫描。<br />
(4).索引列上&gt;=代替&gt;<br />
低效：select * from emp where deptno &gt; 3<br />
高效：select * from emp where deptno &gt;=4<br />
两者的区别在于，前者dbms将直接跳到第一个deptno等于4的记录，而后者将首先定位到deptno等于3的记录并且向前扫描到第一个deptno大于3的。<br />
(5).非要对一个使用函数的列启用索引，基于函数的索引是一个较好的方案。</p>
<p>2. 游标的使用：<br />
当在海量的数据表中进行数据的删除、更新、插入操作时，用游标处理的效率是最慢的，但是游标又是必不可少的，所以正确使用游标十分重要：<br />
(1). 在数据抽取的源表中使用时间戳，这样每天的维表数据维护只针对更新日期为最新时间的数据来进行，大大减少需要维护的数据记录数。<br />
(2). 在insert和update维表时都加上一个条件来过滤维表中已经存在的记录，例如：<br />
insert into dim_customer select * from ods_customer where ods_customer.code not exists (dim_customer.code)<br />
ods_customer为数据源表。dim_customer为维表。<br />
(3). 使用显式的游标，因为隐式的游标将会执行两次操作，第一次检索记录，第二次检查too many rows这个exception,而显式游标不执行第二次操作。</p>
<p>3． 据抽取和上载时的sql优化：<br />
(1). Where 子句中的连接顺序：<br />
oracle采用自下而上的顺序解析where子句，根据这个原理，表之间的连接必须写在其他where条件之前，那些可以过滤掉大量记录的条件必须写在where子句的末尾。如：<br />
低效：select * from emp e where sal&gt;5000 and job = ‘manager’ and 25&lt;(select count (*) from emp where mgr=e.empno);<br />
高效：select * from emp e where 25&lt;(select count(*) from emp where mgr=e.empno) and sal&gt;5000 and job=’manager’;<br />
(2). 删除全表时，用truncate 替代 delete,同时注意truncate只能在删除全表时适用，因为truncate是ddl而不是dml。<br />
(3). 尽量多使用commit<br />
只要有可能就在程序中对每个delete,insert,update操作尽量多使用commit,这样系统性能会因为commit所释放的资源而大大提高。<br />
(4). 用exists替代in ，可以提高查询的效率。<br />
(5). 用not exists 替代 not in<br />
(6). 优化group by<br />
提高group by语句的效率，可以将不需要的记录在group by之前过滤掉。如：<br />
低效：select job, avg(sal) from emp group by job having job = ‘president’ or job=’manager’;<br />
高效： select job, avg(sal) from emp having job=’president’ or job=’manager’ group by job;<br />
(7). 有条件的使用union-all 替代 union：这样做排序就不必要了，效率会提高3到5倍。<br />
(8). 分离表和索引<br />
总是将你的表和索引建立在不同的表空间内，决不要将不属于oracle内部系统的对象存放到system表空间内。同时确保数据表空间和索引表空间置于不同的硬盘控制卡控制的硬盘上。</p>
<p><em>原载：<a href="http://www.zhangzhang.net/" target="_blank">姓张那小子</a><br />
北风技术专栏授权发布，谢绝未经本人书面授权的转载。</em></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/zhangzhang/20081014117.shtml/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
