<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>涂0实验室 &#187; 理论</title>
	<atom:link href="http://www.sulong.info/archives/category/%e7%a8%8b%e5%ba%8f/%e7%90%86%e8%ae%ba/feed" rel="self" type="application/rss+xml" />
	<link>http://www.sulong.info</link>
	<description>一个程序员的成长之路</description>
	<lastBuildDate>Fri, 27 Aug 2010 01:54:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Servlet 3.0异步处理</title>
		<link>http://www.sulong.info/archives/366</link>
		<comments>http://www.sulong.info/archives/366#comments</comments>
		<pubDate>Wed, 14 Jul 2010 15:19:29 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[理论]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=366</guid>
		<description><![CDATA[看过Servlet 3.0的规范和API后，可以看出来，所谓异步的HTTP，其实异步的不是HTTP，而是服务器端异步地处理HTTP请求，而HTTP客户端，仍旧是同步的等待服务端的处理结果。一般servlet容器会分配一个线程用来处理一个来自客户端的HTTP请求，在这个线程发送回HTTP响应之前，这个线程只属于这个HTTP请求不能离开处理其它请求。采用Servlet3.0之后，当前的线程可以开启异步处理，开启异步处理的时候会得到一个异步处理上下文对象，之后当前的线程就可以不生成HTTP响应而直接退出去处理其它的HTTP请求，其它线程可以在之后通过异步处理上下文来生成和发送那个HTTP响应。可见所谓的异步HTTP其实只是一种可以让当前的处理线程在不生成响应前就离开，而在之后再处理这个HTTP请求的机制。 从客户端看来，不论是哪种方式，浏览器都在发送完HTTP请求之后，都必须同步的等待服务器端的响应。假如浏览器发送完HTTP请求之后，可以在得到服务器处理结果之前转而处理其它事情，而在未来的某个时刻，当服务器处理完请求后，不需要客户端再发送请求，就可以发响应发回给浏览器，也许那才是真的异步HTTP了。但是这是违反HTTP的有请求才响应，无请求不响应的基本原则的。 HTTP长连接可以让客户端和服务器在同一个TCP连接中做多次请求响应，但是并不能改变客户端和服务器之间的同步请求响应模式。 尽管Servlet3.0的异步功能不能改变HTTP的协议，在本质上让浏览器和服务器之间异步的交互，但是这一功能还是有非常大的意义的。假设接受请求和发送响应的时间分别为Req和Resp，每个请求都要执行一个耗时P的操作O，并且O操作会让调用者阻塞，当在P时间内有n个请求发送过来时，用传统的处理方式，由于P时间内每个线程都不能处理完，servlet容器要分配F(n) = n个线程处理请求，如下图所示: 而用Servlet3.0的异步处理时，处理线程可以开启单一线程去做那个耗时P的操作，而把当前请求的异步处理上下文放入一个等待队列中，自己则接着处理其它的请求，假设这个开启异步，加入异步处理上下文的操作需要时间A，那么需要开启F(n) = n*(A+Req+Resp)/(P + Req + Resp) + 1个线程就可以在P时间内处理完所有请求。如下图所示： 假如执行操作O可以不阻塞，耗时C就返回, 那么n客户端每获得一次资源，需要发送f(n) = n*P / (Req + C + Resp) 次请求，而用异步处理的时候，只需要n次请求。可见当A足够小于P时，O阻塞访问时，异步可以用更少的线程处理更多的请求；O非阻塞访问时，异步可以减少请求次数。 以web QQ为例来看看。用户发送消息时，假设服务器分发消息耗时P远远大于开启异步和把消息放到待分发队列的耗时A，那么采用异步处理发送消息，可以用更少的线程处理更多的发送消息请求。用户接受消息，假设平均P时间内用户才有新消息到达，而检查一次新消息的耗时远小于P，那么采用异步则可以减少很多客户端请求。]]></description>
			<content:encoded><![CDATA[<p>看过Servlet 3.0的规范和API后，可以看出来，所谓异步的HTTP，其实异步的不是HTTP，而是服务器端异步地处理HTTP请求，而HTTP客户端，仍旧是同步的等待服务端的处理结果。一般servlet容器会分配一个线程用来处理一个来自客户端的HTTP请求，在这个线程发送回HTTP响应之前，这个线程只属于这个HTTP请求不能离开处理其它请求。采用Servlet3.0之后，当前的线程可以开启异步处理，开启异步处理的时候会得到一个异步处理上下文对象，之后当前的线程就可以不生成HTTP响应而直接退出去处理其它的HTTP请求，其它线程可以在之后通过异步处理上下文来生成和发送那个HTTP响应。可见所谓的异步HTTP其实只是一种可以让当前的处理线程在不生成响应前就离开，而在之后再处理这个HTTP请求的机制。</p>
<p>从客户端看来，不论是哪种方式，浏览器都在发送完HTTP请求之后，都必须同步的等待服务器端的响应。假如浏览器发送完HTTP请求之后，可以在得到服务器处理结果之前转而处理其它事情，而在未来的某个时刻，当服务器处理完请求后，不需要客户端再发送请求，就可以发响应发回给浏览器，也许那才是真的异步HTTP了。但是这是违反HTTP的有请求才响应，无请求不响应的基本原则的。  HTTP长连接可以让客户端和服务器在同一个TCP连接中做多次请求响应，但是并不能改变客户端和服务器之间的同步请求响应模式。</p>
<p>尽管Servlet3.0的异步功能不能改变HTTP的协议，在本质上让浏览器和服务器之间异步的交互，但是这一功能还是有非常大的意义的。假设接受请求和发送响应的时间分别为Req和Resp，每个请求都要执行一个耗时P的操作O，并且O操作会让调用者阻塞，当在P时间内有n个请求发送过来时，用传统的处理方式，由于P时间内每个线程都不能处理完，servlet容器要分配F(n) = n个线程处理请求，如下图所示:</p>
<p><a href="http://www.sulong.info/wp-content/uploads/2010/07/old_servlet.jpeg"><img class="size-full wp-image-369 alignnone" title="old_servlet_thread_style" src="http://www.sulong.info/wp-content/uploads/2010/07/old_servlet.jpeg" alt="" width="692" height="443" /></a></p>
<p>而用Servlet3.0的异步处理时，处理线程可以开启单一线程去做那个耗时P的操作，而把当前请求的异步处理上下文放入一个等待队列中，自己则接着处理其它的请求，假设这个开启异步，加入异步处理上下文的操作需要时间A，那么需要开启F(n) = n*(A+Req+Resp)/(P + Req + Resp) + 1个线程就可以在P时间内处理完所有请求。如下图所示：</p>
<p><a href="http://www.sulong.info/wp-content/uploads/2010/07/servlet_3.jpeg"><img class="alignnone size-full wp-image-371" title="servlet3_asyn_thread_style" src="http://www.sulong.info/wp-content/uploads/2010/07/servlet_3.jpeg" alt="" width="692" height="518" /></a></p>
<p>假如执行操作O可以不阻塞，耗时C就返回, 那么n客户端每获得一次资源，需要发送f(n) = n*P / (Req + C + Resp) 次请求，而用异步处理的时候，只需要n次请求。可见当A足够小于P时，O阻塞访问时，异步可以用更少的线程处理更多的请求；O非阻塞访问时，异步可以减少请求次数。</p>
<p>以web QQ为例来看看。用户发送消息时，假设服务器分发消息耗时P远远大于开启异步和把消息放到待分发队列的耗时A，那么采用异步处理发送消息，可以用更少的线程处理更多的发送消息请求。用户接受消息，假设平均P时间内用户才有新消息到达，而检查一次新消息的耗时远小于P，那么采用异步则可以减少很多客户端请求。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/366/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>web服务器集群</title>
		<link>http://www.sulong.info/archives/312</link>
		<comments>http://www.sulong.info/archives/312#comments</comments>
		<pubDate>Mon, 03 Aug 2009 06:34:04 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[理论]]></category>
		<category><![CDATA[经验]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=312</guid>
		<description><![CDATA[什么是集群 计算机集群（以下简称集群）在维基百科上被定义为一组相互连接的计算机，紧密的工作在一起，以至于在很多方面看来，它们都像是一台机器。 集群的好处 集群可能能给我们带来很多好处，其中负载均衡(loadbalance)和故障恢复(failover)一般是最常用的。负载均衡是将系统的负载分派到集群内不同的计算机上，让每个节点都不至于太忙或太闲，通过增加集群中计算机的数量，可以提升整体的负载能力。故障恢复是指在集群中某个节点发生故障时，其它的节点代替它们继续工作，这样整个系统依旧能对外提供服务。 web服务器集群的特点 对于web服务器来说，集群就是让一组计算机对外像一台web服务器一样运行。web服务器的特点是它通过http协议与客户端交互，而http协议的工作机制是请求响应模式的。web服务器的集群要能把客户端的http请求发送到集群内各个节点上，实现loadbalance，并能探测到各节点的工作情况，在某个节点失效的时候，不再把http请求发送到该节点上。 有状态与无状态 web程序本身是否有状态对实现集群的方法和难以度有很大的影响。如果web程序和客户端交互的记录下了一些状态信息，并在处理之后的请求时需要知道这样的信息，那么这个程序就是有状态的。比如，登录功能，当用户正确登录后，web程序会记录下用户的登录状态，当用户访问其它的页面时，web程序会参照用户的登录信息做不同的处理。在实现集群的时候，有状态的程序要复杂些，因为必须保证处理请求的节点上能有该用户的状态信息。对于无状态的程序，则没有这个问题，请求被分发到任何节点都是一样的，没有额外的维护状态的工作。 为了保证处理请求的节点上能有状态信息，要么在多个节点上复制程序的状态，要么采用否种策略保证将请求正确的发送到具有相应状态的节点上。如上面的例子，要么把用户登录的信息复制到集群的所有节点上，以保证无论之后请求发送到哪个节点上，都能够找得到登录信息，要么每次都把这个用户的请求发送到同一个节点上，就像mod_jk的sticky_session那样。 多线程与多进程 php,ruby,python等脚本语言往往采用无状态的结构，而java往往采用有状态的结构。并非语言决定了它们的工作方式，更多的是一种习惯。 java web服务在运行时是一个常驻内存的进程，用不同的线程处理用户请求。当处理一个http请求的线程结束后，保留在该进程内的信息并没有消失，因为进程还在。因此，可以很方便的把一些交互信息放到java进程的内存中，在多个线程间共享。在加上又有好用的HttpSession类，这样在java ee里把用户信息保存到session中，是一件非常容易的事，程序员们也自然的就采用的，导致了java web程序成了有状态的。如果完全不用session等，java web程序也能做到无状态。 和java的单进程，多线程工作方式不同，php等脚本语言采用了多进程的工作方式。当有一个http请求到来时，web服务器开启一个新的进程，这个进程调用脚本语言的解释器来运行脚本处理请求，处理结束后进程退出。如果要在多个进程间共享信息，就得采用外部的介质，DB就成了最好的选择。 本质上来说，只要需要记录会话的状态，就肯定有状态，差别只是把状态放到什么地方。java ee里往往把它放到应用程序的内存里，而php等则往往放到db里。]]></description>
			<content:encoded><![CDATA[<h3>什么是集群</h3>
<p><a href="http://en.wikipedia.org/wiki/Cluster_%28computing%29">计算机集群</a>（以下简称集群）在维基百科上被定义为一组相互连接的计算机，紧密的工作在一起，以至于在很多方面看来，它们都像是一台机器。</p>
<h3>集群的好处</h3>
<p>集群可能能给我们带来很多好处，其中负载均衡(loadbalance)和故障恢复(failover)一般是最常用的。负载均衡是将系统的负载分派到集群内不同的计算机上，让每个节点都不至于太忙或太闲，通过增加集群中计算机的数量，可以提升整体的负载能力。故障恢复是指在集群中某个节点发生故障时，其它的节点代替它们继续工作，这样整个系统依旧能对外提供服务。</p>
<h3>web服务器集群的特点</h3>
<p>对于web服务器来说，集群就是让一组计算机对外像一台web服务器一样运行。web服务器的特点是它通过http协议与客户端交互，而http协议的工作机制是请求响应模式的。web服务器的集群要能把客户端的http请求发送到集群内各个节点上，实现loadbalance，并能探测到各节点的工作情况，在某个节点失效的时候，不再把http请求发送到该节点上。</p>
<h3>有状态与无状态</h3>
<p>web程序本身是否有状态对实现集群的方法和难以度有很大的影响。如果web程序和客户端交互的记录下了一些状态信息，并在处理之后的请求时需要知道这样的信息，那么这个程序就是有状态的。比如，登录功能，当用户正确登录后，web程序会记录下用户的登录状态，当用户访问其它的页面时，web程序会参照用户的登录信息做不同的处理。在实现集群的时候，有状态的程序要复杂些，因为必须保证处理请求的节点上能有该用户的状态信息。对于无状态的程序，则没有这个问题，请求被分发到任何节点都是一样的，没有额外的维护状态的工作。</p>
<p>为了保证处理请求的节点上能有状态信息，要么在多个节点上复制程序的状态，要么采用否种策略保证将请求正确的发送到具有相应状态的节点上。如上面的例子，要么把用户登录的信息复制到集群的所有节点上，以保证无论之后请求发送到哪个节点上，都能够找得到登录信息，要么每次都把这个用户的请求发送到同一个节点上，就像mod_jk的sticky_session那样。</p>
<h3>多线程与多进程</h3>
<p>php,ruby,python等脚本语言往往采用无状态的结构，而java往往采用有状态的结构。并非语言决定了它们的工作方式，更多的是一种习惯。</p>
<p>java web服务在运行时是一个常驻内存的进程，用不同的线程处理用户请求。当处理一个http请求的线程结束后，保留在该进程内的信息并没有消失，因为进程还在。因此，可以很方便的把一些交互信息放到java进程的内存中，在多个线程间共享。在加上又有好用的HttpSession类，这样在java ee里把用户信息保存到session中，是一件非常容易的事，程序员们也自然的就采用的，导致了java web程序成了有状态的。如果完全不用session等，java web程序也能做到无状态。</p>
<p>和java的单进程，多线程工作方式不同，php等脚本语言采用了多进程的工作方式。当有一个http请求到来时，web服务器开启一个新的进程，这个进程调用脚本语言的解释器来运行脚本处理请求，处理结束后进程退出。如果要在多个进程间共享信息，就得采用外部的介质，DB就成了最好的选择。</p>
<p>本质上来说，只要需要记录会话的状态，就肯定有状态，差别只是把状态放到什么地方。java ee里往往把它放到应用程序的内存里，而php等则往往放到db里。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/312/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>IO和性能</title>
		<link>http://www.sulong.info/archives/232</link>
		<comments>http://www.sulong.info/archives/232#comments</comments>
		<pubDate>Fri, 03 Jul 2009 08:16:03 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[理论]]></category>
		<category><![CDATA[程序]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[性能]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=232</guid>
		<description><![CDATA[最近几天看了几家互联网公司的和架构有关的PPT，有支付宝，linkedin，douban等。这些公司所使用的具体的技术有差别，但是为了能做到支持大规模访问，他们都在与缓慢的IO做斗争！ 比如说豆瓣网的历次架构变迁，不是因为磁盘IO成为瓶颈，就是因为网络IO成为瓶颈。如果能把IO的问题解决掉，那么对于互联网企业来说，性能问题就解决掉一半了，我想。 与飞速的CPU和内存相比，磁盘和网络的IO慢如蜗牛，这是问题的根源。如果没有大规模廉价而又足够快的存储方案出现的话，这个问题还将继续下去。我们只能期待这一革命性的技术出现来从根本上解决这一问题吧！ 那对于现在的我们该怎么办呢？大家的想法可能都是一样的，一是加快IO速度，二是避免不必要的IO。豆瓣曾经通过购买更高性能的硬盘来解决这个问题，如果想要更好的效果，需要投入更多的资金来购买整套的高性能存储方案，但是这成本太高了，很多公司后来都会放弃。于是大部分公司都会极力采用后者，就是避免不必要的IO，缓存就是用来做这样的事的。 将低速介质上的数据放到高速介质上，访问者先访问高速介质，在找不到需要数据时才访问低速介质，以此来提升访问数据的速度，这样的技术就是缓存了。设在一段时间内有m次没有命中缓存，n次命中，而访问一次缓存的时间是t1， 访问慢速介质的时间是t2，那么为了是缓存有效就得满足不等式： m * (t1 + t2) + n * t1 < (m + n) * t2， 于是有 m / n < t2 / t1 -1 。由此可见，在介质的速度比一定的情况下，命中比率要高于一定的值，缓存才有效果。提高命中比率，就是要把那些最常用的数据放到缓存里。另一方面，缓存里数据如果被修改了，就要同步到低速存储介质中，同样的，如果低速存储介质的数据被修改了，也要同步到缓存里。如果加上同步的开销，就需要更高的命中率。提高命中率和保证数据的同步，是使用缓存的两个艰巨的任务。 豆瓣网使用memcache，还使用专门的nigix服务器来提供图片的服务，其实也是cache。linkedin则使用了数十台大内存的服务器作为缓存服务器，运行着用c++写的专门的缓存程序。可见这些网站在使用缓存方面都是不遗余力呀。如果能把缓存用好，那么就把一大半的IO问题解决掉了。 IO往往会成为程序的瓶颈，因此，程序员应当时刻的注意，你写的代码是否在进行IO操作，是否可以减少IO操作，等等。]]></description>
			<content:encoded><![CDATA[<p>最近几天看了几家互联网公司的和架构有关的PPT，有支付宝，linkedin，douban等。这些公司所使用的具体的技术有差别，但是为了能做到支持大规模访问，他们都在与缓慢的IO做斗争！ 比如说豆瓣网的历次架构变迁，不是因为磁盘IO成为瓶颈，就是因为网络IO成为瓶颈。如果能把IO的问题解决掉，那么对于互联网企业来说，性能问题就解决掉一半了，我想。</p>
<p>与飞速的CPU和内存相比，磁盘和网络的IO慢如蜗牛，这是问题的根源。如果没有大规模廉价而又足够快的存储方案出现的话，这个问题还将继续下去。我们只能期待这一革命性的技术出现来从根本上解决这一问题吧！</p>
<p>那对于现在的我们该怎么办呢？大家的想法可能都是一样的，一是加快IO速度，二是避免不必要的IO。豆瓣曾经通过购买更高性能的硬盘来解决这个问题，如果想要更好的效果，需要投入更多的资金来购买整套的高性能存储方案，但是这成本太高了，很多公司后来都会放弃。于是大部分公司都会极力采用后者，就是避免不必要的IO，缓存就是用来做这样的事的。</p>
<p>将低速介质上的数据放到高速介质上，访问者先访问高速介质，在找不到需要数据时才访问低速介质，以此来提升访问数据的速度，这样的技术就是缓存了。设在一段时间内有m次没有命中缓存，n次命中，而访问一次缓存的时间是t1， 访问慢速介质的时间是t2，那么为了是缓存有效就得满足不等式： m * (t1 + t2) + n * t1 < (m + n) * t2， 于是有 m / n < t2 / t1 -1 。由此可见，在介质的速度比一定的情况下，命中比率要高于一定的值，缓存才有效果。提高命中比率，就是要把那些最常用的数据放到缓存里。另一方面，缓存里数据如果被修改了，就要同步到低速存储介质中，同样的，如果低速存储介质的数据被修改了，也要同步到缓存里。如果加上同步的开销，就需要更高的命中率。提高命中率和保证数据的同步，是使用缓存的两个艰巨的任务。</p>
<p>豆瓣网使用memcache，还使用专门的nigix服务器来提供图片的服务，其实也是cache。linkedin则使用了数十台大内存的服务器作为缓存服务器，运行着用c++写的专门的缓存程序。可见这些网站在使用缓存方面都是不遗余力呀。如果能把缓存用好，那么就把一大半的IO问题解决掉了。</p>
<p>IO往往会成为程序的瓶颈，因此，程序员应当时刻的注意，你写的代码是否在进行IO操作，是否可以减少IO操作，等等。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/232/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>DRY, Don&#8217;t Repeat Yourself!</title>
		<link>http://www.sulong.info/archives/231</link>
		<comments>http://www.sulong.info/archives/231#comments</comments>
		<pubDate>Wed, 01 Jul 2009 08:59:34 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[理论]]></category>
		<category><![CDATA[思考]]></category>
		<category><![CDATA[经验]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=231</guid>
		<description><![CDATA[DRY，就是不要写重复的代码，这也是程序设计的一个黄金准则之一。 1 引申自关注点分离 其实这一条准则，也是从关注点分离引申而来的。如果完成相同或相似功能的代码片段，在一个程序的很多地方出现，那么无疑会使包含它的代码多了一个关注点。把相同或相似的代码抽象出来，放在一个地方，这样就可以使调用者减少一个关注点，同时将所有的对同类问题的关注合并到一个地方。比如说，判断一个用户是否登录，这一功能被很多地方使用，如果把这一功能包装成函数放到一个地方，需要使用的地方只要引用一下函数就可以了，这样引用者就不用关心如何判断一个用户是否登录了。 2 好处 2.1 提高效率 同样的功能，完成一次就可以了，如果每次要使用轮子的时候，都重复发明轮子，那是对人类智慧的浪费。如果发明一个万用轮子不容易，那么发明一个够用的可以反复使用的轮子就可以了。 2.2 更易读 如过你打开一个程序的源代码，发现有大量类似又稍有差别的代码，你还有多少心情读下去吗？要读下去的话，你就得像diff工具一样去比较类似代码间的细微差别，还要揣摩它的含义。这样的代码读起来太痛苦了。因此，如果没有重复的代码，就没有这份痛苦。 2.3 更易维护 如果你用类似的算法，重复写了很多的程序，结果却发现这个算法有个错误，那你不得不小心翼翼的找到所有的这样的程序，并一个一个又一个的修正。那是一个多么无聊的工作呀。如果漏掉了，或者将其中的某些一不小心修改错了，还得回头再重新修改，那台痛苦了！所以充斥着copy&#038;paste的代码，是维护者的噩梦。 3 怎么做 程序语言和编程方法的进步，也就是人们在实践DRY的过程。要做到DRY，就是要不断的通过抽象，把重复的功能抽象并包装起来。我们先是有了函数和子程序，后来有了类和方法，等等。我知道，为了DRY，还会有新的工具和方法论被发明。]]></description>
			<content:encoded><![CDATA[<p>DRY，就是不要写重复的代码，这也是程序设计的一个黄金准则之一。</p>
<h2>1 引申自关注点分离</h2>
<p>其实这一条准则，也是从<a href="http://www.sulong.info/archives/99">关注点分离</a>引申而来的。如果完成相同或相似功能的代码片段，在一个程序的很多地方出现，那么无疑会使包含它的代码多了一个关注点。把相同或相似的代码抽象出来，放在一个地方，这样就可以使调用者减少一个关注点，同时将所有的对同类问题的关注合并到一个地方。比如说，判断一个用户是否登录，这一功能被很多地方使用，如果把这一功能包装成函数放到一个地方，需要使用的地方只要引用一下函数就可以了，这样引用者就不用关心如何判断一个用户是否登录了。</p>
<h2>2 好处</h2>
<h3>2.1 提高效率</h3>
<p>同样的功能，完成一次就可以了，如果每次要使用轮子的时候，都重复发明轮子，那是对人类智慧的浪费。如果发明一个万用轮子不容易，那么发明一个够用的可以反复使用的轮子就可以了。</p>
<h3>2.2 更易读</h3>
<p>如过你打开一个程序的源代码，发现有大量类似又稍有差别的代码，你还有多少心情读下去吗？要读下去的话，你就得像diff工具一样去比较类似代码间的细微差别，还要揣摩它的含义。这样的代码读起来太痛苦了。因此，如果没有重复的代码，就没有这份痛苦。</p>
<h3>2.3 更易维护</h3>
<p>如果你用类似的算法，重复写了很多的程序，结果却发现这个算法有个错误，那你不得不小心翼翼的找到所有的这样的程序，并一个一个又一个的修正。那是一个多么无聊的工作呀。如果漏掉了，或者将其中的某些一不小心修改错了，还得回头再重新修改，那台痛苦了！所以充斥着copy&#038;paste的代码，是维护者的噩梦。</></p>
<h2>3 怎么做</h2>
<p>程序语言和编程方法的进步，也就是人们在实践DRY的过程。要做到DRY，就是要不断的通过抽象，把重复的功能抽象并包装起来。我们先是有了函数和子程序，后来有了类和方法，等等。我知道，为了DRY，还会有新的工具和方法论被发明。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/231/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
