<?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>PHP博客-专注于PHP技术</title>
	<atom:link href="http://www.phpboke.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.phpboke.com</link>
	<description>php学习交流博客phpboke.com</description>
	<lastBuildDate>Tue, 15 May 2012 15:26:53 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>.htaccess伪静态实例记录</title>
		<link>http://www.phpboke.com/htaccess-static.html</link>
		<comments>http://www.phpboke.com/htaccess-static.html#comments</comments>
		<pubDate>Tue, 15 May 2012 15:26:53 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=826</guid>
		<description><![CDATA[原始 index.php 伪静态 index.html
 RewriteRule ^index\.html$ index.php
原始 news/detail.php?id=2  伪静态  news/detail_2.html
RewriteRule ^news/detail_([0-9]{1,})\.html$ news/detail.php?id=$1
原始 index.php?cid=2&#38;id=3  伪静态 2-3.html
RewriteRule ([a-zA-Z]{1,})-([0-9]{1,})\.html$ index.php?cid=$1&#38;id=$2
([a-zA-Z]{1,})-([0-9]{1,})\.html$是规则，index.php?action=$1&#38;id=$2是要替换的格式，$1代表第一个括号匹配的值，$2代表第二个，如此类推！！
]]></description>
			<content:encoded><![CDATA[<p><strong>原始 index.php 伪静态 index.html</strong></p>
<p><span style="white-space: pre;"><strong> </strong></span><strong><span style="color: #008000;">RewriteRule ^index\.html$ index.php</span></strong></p>
<p><strong>原始 news/detail.php?id=2  伪静态  news/detail_2.html</strong></p>
<p><strong><span style="color: #008000;">RewriteRule ^news/detail_([0-9]{1,})\.html$ news/detail.php?id=$1</span></strong></p>
<p><strong>原始 index.php?cid=2&amp;id=3  伪静态 2-3.html</strong></p>
<p><strong><span style="color: #008000;">RewriteRule ([a-zA-Z]{1,})-([0-9]{1,})\.html$ index.php?cid=$1&amp;id=$2</span></strong></p>
<p><strong><span style="color: #000000;">([a-zA-Z]{1,})-([0-9]{1,})\.html$是规则，index.php?action=$1&amp;id=$2是要替换的格式，$1代表第一个括号匹配的值，$2代表第二个，如此类推！！</span></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/htaccess-static.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP实现MVC开发得最简单的方法——单点入口</title>
		<link>http://www.phpboke.com/php-mvc-sigle.html</link>
		<comments>http://www.phpboke.com/php-mvc-sigle.html#comments</comments>
		<pubDate>Sat, 17 Mar 2012 15:35:40 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[PHP高级开发]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=823</guid>
		<description><![CDATA[今天就开始详细的写写我对MVC的一些理解，以及我在开发过程中实现自己的一个框架的一个流程。其中或许说的不正确，还望指正！
网站关于MVC的教材很多了，我这里不具体说了，不明白的，推荐自己上百度搜索下“MVC&#8221;，相信可以找到你想要的东西的。这里我谈谈在PHP实际开发中，我对MVC的理解。M，module，主要任务是把数据库或者其他文件系统的数据按照我们需要的方式读取出来。V，view，我的理解是主要负责页面的先是，把数据以html的形式显示给用户。C，controller，主要负责业务逻辑，比如说你要显示登陆界面，就需要调用一个控制器userController的方法loginAction来显示（可能这个不需要调用module），再比如你进行登陆检查就可以调用userController的方法checkAction来进行逻辑处理。(感觉Verdana的指正^_^)。
引用
M是指model。Controller 并不参与业务逻辑，整个业务逻辑部分应该是放在 Model 层中的。Controller 只起到分发请求的作用，也就是说得到当前的 Request，决定调用哪个 Model 获取数据，然后再赋值给哪个 View 来渲染页面
具体实现MVC，我觉得最好还是要做到单点入口。
什么是单点入口呢？所谓单点入口就是整个应用程序只有一个入口，所有的实现都通过这个入口来转发，比如说在上面我们就使用index.php作为程序的单点入口，当然这个是可以由你自己任意控制的。
为什么要做到单点入口呢？单点入口有几大好处：第一、一些系统全局处理的变量，类，方法都可以在这里进行处理。比如说你要对数据进行初步的过滤，你要模拟session处理，你要定义一些全局变量，甚至你要注册一些对象或者变量到注册器里面（主要是实现在全局，具体你可以参考我先前翻译的一些文章《在PHP中使用全局变量》）。第二、程序的架构更加清晰明了。当然好处还有很多的，我也不一一列举了，具体你可以去体会。
当然单点入口也存在一些不足，比如你系统大了后，不可能只一个点做为入口，尤其系统存在两个完全不相关的功能时候，不过很高兴的说，这个是可以扩展，你可以扩展多个入口。比如说在最近一个大项目中，后台的管理和前台是不相关的，所以我就会有两个入口，一个是index.php一个是admin.php。但这不不是说单点入口不好（具体含义你可以揣摩下）。
那么，如何实现单点入口呢？这是我本节的重点。一般来说都是通过url的地址映射实现的（前面我有一篇文章说到这个：《回答PHPCHINA上的几个问题:URL映射》，里面实现了单点入口的核心，这里我具体实现，并演示下）。单点入口最关键的就是通过url传递参数来实现程序的分配，具体说，比如：地址是index.php?controller=test&#38;action=test，这就通过index.php把请求转发到对应的testController文件中，并执行其对应的testAction方法（这里的控制器和方法的命名都参考了Zend Framework的思想）。
下面我们用最简单的方法是来实现上面说的单点入口（记住：简单起见，我这里没有使用URL映射了）
/index.php
&#60;?
/**
* MVC演示demo
* 仅仅实现最基本的MVC功能，不包含安全处理，数据过滤，及其他优化措施。
*/
define(&#8216;SITE_PATH&#8217;,str_replace(&#8221;,&#8217;/',dirname(__FILE__)));//定义系统目录
$controller=(!empty($_GET['controller']))?$_GET['controller']:&#8217;index&#8217;;//获取控制器,默认index
$action=(!empty($_GET['action']))?$_GET['action']:&#8217;index&#8217;;//方法名称，默认index
$controller_name=$controller.&#8217;Controller&#8217;;
$controller_file=SITE_PATH.&#8217;/app/controller/&#8217;.$controller_name.&#8217;.class.php&#8217;;//获取控制器文件
if(file_exists($controller_file)){
require_once($controller_file);
$controller=new $controller_name();
$controller-&#62;{$action.&#8217;Action&#8217;}();
}else{
die(&#8216;找不到对应的控制器！&#8217;);
}
?&#62;
对应的一个演示demo
/app/controller/testController.class.php（注意路径）
&#60;?
/**
* MVC演示demo
* 仅仅实现最基本的MVC功能，不包含安全处理，数据过滤，及其他优化措施。
*/
class testController
{
function testAction(){
echo &#8216;Hello,World!&#8217;;
}
}
?&#62;
打开浏览器，输入http://path/to/yoursite/index.php?controller=test&#38;action=test（注意相应的修改你的路径），如果你看到Hello,World!说明MVC第一步，单点入口成功了！
]]></description>
			<content:encoded><![CDATA[<p>今天就开始详细的写写我对MVC的一些理解，以及我在开发过程中实现自己的一个框架的一个流程。其中或许说的不正确，还望指正！<br />
网站关于MVC的教材很多了，我这里不具体说了，不明白的，推荐自己上百度搜索下“MVC&#8221;，相信可以找到你想要的东西的。这里我谈谈在PHP实际开发中，我对MVC的理解。M，module，主要任务是把数据库或者其他文件系统的数据按照我们需要的方式读取出来。V，view，我的理解是主要负责页面的先是，把数据以html的形式显示给用户。C，controller，主要负责业务逻辑，比如说你要显示登陆界面，就需要调用一个控制器userController的方法loginAction来显示（可能这个不需要调用module），再比如你进行登陆检查就可以调用userController的方法checkAction来进行逻辑处理。(感觉Verdana的指正^_^)。<span id="more-823"></span></p>
<p>引用</p>
<p>M是指model。Controller 并不参与业务逻辑，整个业务逻辑部分应该是放在 Model 层中的。Controller 只起到分发请求的作用，也就是说得到当前的 Request，决定调用哪个 Model 获取数据，然后再赋值给哪个 View 来渲染页面</p>
<p>具体实现MVC，我觉得最好还是要做到单点入口。<br />
什么是单点入口呢？所谓单点入口就是整个应用程序只有一个入口，所有的实现都通过这个入口来转发，比如说在上面我们就使用index.php作为程序的单点入口，当然这个是可以由你自己任意控制的。<br />
为什么要做到单点入口呢？单点入口有几大好处：第一、一些系统全局处理的变量，类，方法都可以在这里进行处理。比如说你要对数据进行初步的过滤，你要模拟session处理，你要定义一些全局变量，甚至你要注册一些对象或者变量到注册器里面（主要是实现在全局，具体你可以参考我先前翻译的一些文章《在PHP中使用全局变量》）。第二、程序的架构更加清晰明了。当然好处还有很多的，我也不一一列举了，具体你可以去体会。<br />
当然单点入口也存在一些不足，比如你系统大了后，不可能只一个点做为入口，尤其系统存在两个完全不相关的功能时候，不过很高兴的说，这个是可以扩展，你可以扩展多个入口。比如说在最近一个大项目中，后台的管理和前台是不相关的，所以我就会有两个入口，一个是index.php一个是admin.php。但这不不是说单点入口不好（具体含义你可以揣摩下）。<br />
那么，如何实现单点入口呢？这是我本节的重点。一般来说都是通过url的地址映射实现的（前面我有一篇文章说到这个：《回答PHPCHINA上的几个问题:URL映射》，里面实现了单点入口的核心，这里我具体实现，并演示下）。单点入口最关键的就是通过url传递参数来实现程序的分配，具体说，比如：地址是index.php?controller=test&amp;action=test，这就通过index.php把请求转发到对应的testController文件中，并执行其对应的testAction方法（这里的控制器和方法的命名都参考了Zend Framework的思想）。<br />
下面我们用最简单的方法是来实现上面说的单点入口（记住：简单起见，我这里没有使用URL映射了）<br />
/index.php<br />
&lt;?<br />
/**<br />
* MVC演示demo<br />
* 仅仅实现最基本的MVC功能，不包含安全处理，数据过滤，及其他优化措施。<br />
*/<br />
define(&#8216;SITE_PATH&#8217;,str_replace(&#8221;,&#8217;/',dirname(__FILE__)));//定义系统目录</p>
<p>$controller=(!empty($_GET['controller']))?$_GET['controller']:&#8217;index&#8217;;//获取控制器,默认index<br />
$action=(!empty($_GET['action']))?$_GET['action']:&#8217;index&#8217;;//方法名称，默认index</p>
<p>$controller_name=$controller.&#8217;Controller&#8217;;<br />
$controller_file=SITE_PATH.&#8217;/app/controller/&#8217;.$controller_name.&#8217;.class.php&#8217;;//获取控制器文件<br />
if(file_exists($controller_file)){<br />
require_once($controller_file);<br />
$controller=new $controller_name();<br />
$controller-&gt;{$action.&#8217;Action&#8217;}();<br />
}else{<br />
die(&#8216;找不到对应的控制器！&#8217;);<br />
}<br />
?&gt;</p>
<p>对应的一个演示demo<br />
/app/controller/testController.class.php（注意路径）<br />
&lt;?<br />
/**<br />
* MVC演示demo<br />
* 仅仅实现最基本的MVC功能，不包含安全处理，数据过滤，及其他优化措施。<br />
*/<br />
class testController<br />
{<br />
function testAction(){<br />
echo &#8216;Hello,World!&#8217;;<br />
}<br />
}<br />
?&gt;</p>
<p>打开浏览器，输入http://path/to/yoursite/index.php?controller=test&amp;action=test（注意相应的修改你的路径），如果你看到Hello,World!说明MVC第一步，单点入口成功了！</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/php-mvc-sigle.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP 单一入口程序闲聊</title>
		<link>http://www.phpboke.com/php-sigle-inter.html</link>
		<comments>http://www.phpboke.com/php-sigle-inter.html#comments</comments>
		<pubDate>Sat, 17 Mar 2012 15:27:31 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[PHP高级开发]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php单一入口]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=820</guid>
		<description><![CDATA[什么是单一入口应用程序？
在解释什么是单一入口应用程序之前，我们先来看看传统的 web 应用程序。
news.php 显示新闻列表
news_edit.php 显示新闻编辑页面
这两个页面不但分别实现了两个功能，还成为了应用程序的两个入口。
那什么是入口啊？
打个比方，大家上 WC，都是男生进一个门，女生进一个门。这两个门就是 WC 的两个入口。
呵呵，上面的例子应该很好理解吧。那稍微变换一下，单一入口的概念就很容易理解了。
现在我们是进一个公共 WC，不管男女都是从最外面的入口进入，交了钱以后才分别进两个门。那最外面的入口就是这个 WC 的单一入口。
所以单一入口的应用程序实际上就是说用一个文件处理所有的 HTTP 请求。例如不管是新闻列表功能还是新闻编辑功能，都是从浏览器访问 index.php 文件。这个 index.php 文件就是这个应用程序的单一入口。
index.php 如何知道用户是要使用哪一个功能呢？
很简单，我们访问 index.php 时跟上一个特定的参数就行了。例如 index.php?action=news 就是显示新闻列表，而 index.php?action=news_edit 就是新闻编辑。
而在 index.php 里面，仅用两行代码就可以实现这种效果。
&#60;?php
$action = $_GET['action'] == &#8221; ? &#8216;index&#8217; : $_GET['action'];
include(&#8216;files/&#8217; . $action . &#8216;.php&#8217;);
?&#62;
上面的代码中，第一行是从 url 中取出 action 参数。如果没有提供 action 参数，就设置一个默认的 &#8216;index&#8217; 作为参数。
第二行代码就是根据 $action 参数调用不同的代码文件，从而实现单一入口对应不同功能的效果。
单一入口应用程序的入口文件很复杂？
有些朋友可能以为单一入口程序的 index.php 会像面条一样复杂，其实是误解。
例如我现在的应用程序入口文件只有下面几行：
&#60;?php
define(&#8216;APP&#8217;,    realpath(&#8216;../libs/website&#8217;));
define(&#8216;LANG&#8217;,    &#8216;gb2312&#8242;);
define(&#8216;DEBUG&#8217;,     [...]]]></description>
			<content:encoded><![CDATA[<p><strong>什么是单一入口应用程序？</strong></p>
<p>在解释什么是单一入口应用程序之前，我们先来看看传统的 web 应用程序。<br />
news.php 显示新闻列表<br />
news_edit.php 显示新闻编辑页面<br />
这两个页面不但分别实现了两个功能，还成为了应用程序的两个入口。</p>
<p>那什么是入口啊？<br />
打个比方，大家上 WC，都是男生进一个门，女生进一个门。这两个门就是 WC 的两个入口。<span id="more-820"></span></p>
<p>呵呵，上面的例子应该很好理解吧。那稍微变换一下，单一入口的概念就很容易理解了。<br />
现在我们是进一个公共 WC，不管男女都是从最外面的入口进入，交了钱以后才分别进两个门。那最外面的入口就是这个 WC 的单一入口。</p>
<p>所以单一入口的应用程序实际上就是说用一个文件处理所有的 HTTP 请求。例如不管是新闻列表功能还是新闻编辑功能，都是从浏览器访问 index.php 文件。这个 index.php 文件就是这个应用程序的单一入口。</p>
<p><strong>index.php 如何知道用户是要使用哪一个功能呢？</strong></p>
<p>很简单，我们访问 index.php 时跟上一个特定的参数就行了。例如 index.php?action=news 就是显示新闻列表，而 index.php?action=news_edit 就是新闻编辑。</p>
<p>而在 index.php 里面，仅用两行代码就可以实现这种效果。<br />
&lt;?php<br />
$action = $_GET['action'] == &#8221; ? &#8216;index&#8217; : $_GET['action'];<br />
include(&#8216;files/&#8217; . $action . &#8216;.php&#8217;);<br />
?&gt;</p>
<p>上面的代码中，第一行是从 url 中取出 action 参数。如果没有提供 action 参数，就设置一个默认的 &#8216;index&#8217; 作为参数。<br />
第二行代码就是根据 $action 参数调用不同的代码文件，从而实现单一入口对应不同功能的效果。</p>
<p><strong>单一入口应用程序的入口文件很复杂？</strong></p>
<p>有些朋友可能以为单一入口程序的 index.php 会像面条一样复杂，其实是误解。<br />
例如我现在的应用程序入口文件只有下面几行：<br />
&lt;?php<br />
define(&#8216;APP&#8217;,    realpath(&#8216;../libs/website&#8217;));<br />
define(&#8216;LANG&#8217;,    &#8216;gb2312&#8242;);<br />
define(&#8216;DEBUG&#8217;,     1);</p>
<p>require(&#8216;../libs/flea1/basic.php&#8217;);<br />
run();<br />
?&gt;<br />
足够简单了吧？</p>
<p>当然了，在 index.php 里面写上一长串 switch case 绝对是拙劣的实现方式。但这纯粹是开发者自己的设计和实现问题，而不是单一入口应用程序这种设计思想的问题。</p>
<p><span style="color: red;">补充说明：</span> 这里提到 switch case 并不是说用了 switch 就代表“落后”、“土气”等。只是说在 index.php 这个入口程序里面写上一堆 switch case 不利于程序的修改和维护，所以是一种不好的用法。</p>
<p><strong>单一入口应用程序的设计思想</strong></p>
<p>当web服务器（apache或者iis）收到一个http请求时，会解析该请求，确定要访问哪一个文件。例如 <a rel="nofollow" href="http://www.xxx.com/news.php" target="_blank">http://www.xxx.com/news.php</a> 的解析结果就是要求web服务器解析 news.php 文件，并返回结果给浏览器。现在看看单一入口应用程序的 index.php 文件，就会发现 index.php 实际上根据 url 参数进行了第二次解析。</p>
<p>完成这个解析的程序一般称为 Dispatcher（中文的准确翻译我也不知道），大概意思就是将不同的请求转发到不同的处理程序进行处理。</p>
<p>在单一入口应用程序中，index.php 和 web服务器一起构成了一个 Dispatcher，根据 http 请求和 url 参数来确定请求的处理程序。</p>
<p>了解了 Dispatcher 的概念后，我们可以发现前面提到的两行代码实际上就是一个最简单的 Dispatcher 实现：<br />
&lt;?php<br />
$action = $_GET['action'] == &#8221; ? &#8216;index&#8217; : $_GET['action'];<br />
include(&#8216;files/&#8217; . $action . &#8216;.php&#8217;);<br />
?&gt;</p>
<p>诚然，对于一个安全、健壮的应用程序，Dispatcher 肯定不是上面那么简单。在调用实际代码前，还会加上各种判断、安全性检查等。例如判断 url 指定的功能是否可以访问以及 url 中包含了无效的参数。</p>
<p>看到这里，朋友们肯定会说：单一入口程序就多了就这样一个 dispatcher ，和我直接做成 news.php、news_edit.php 等单个文件相比有什么好处啊？</p>
<p><strong>单一入口应用程序的优势</strong></p>
<p>单一入口应用程序的所有http请求都是通过 index.php 接收并转发到功能代码去的，所以我们在 index.php 里面就能完成许多实际工作。</p>
<p>这里我只拿安全性检查为例详细说明一下：<br />
由于所有的 http 请求都由 index.php 接收，所以可以进行集中的安全性检查。如果不是单一入口，那么开发者就必须记得在每一个文件的开始加上安全性检查代码（当然，安全性检查代码可以写到另一个文件中，只需要include进来就可以了）。<br />
但我想大家都是懒人，也许记性也不好，难免有忘记的时候。因此要记得在每一个文件前面都加上必要的include可不是件容易做到的事情。</p>
<p>与安全性检查类似。在入口里，我们还可以对url参数和post进行必要的检查和特殊字符过滤、记录日志、访问统计等等各种可以集中处理的任务。</p>
<p>“咦，搞这么多功能，不是会把 index.php 搞得很复杂吗？”<br />
“不会的。只需要把各种功能写到单独的文件，然后在index.php里面include进来就可以了！”</p>
<p>可以看出，由于这些工作都被集中到了 index.php 来完成，可以减轻我们维护其他功能代码的难度。例如在10个文件中保持头部的几个include都一致可不是件让人愉快的事情。</p>
<p><strong>单一入口应用程序的缺点</strong></p>
<p>任何事情都有两面性，单一入口应用程序也不例外。由于所有 http 请求都是针对 index.php，所以应用程序的 url 看起来确实不那么美观。特别是对搜索引擎来说很不友好。</p>
<p>要解决这个问题，可以采用 url 重写、PATHINFO 等方式。但我个人更推荐在前台页面不使用单一入口方式，而是保持多个文件入口。或者两者混用。例如新闻列表采用单独的 news.php 显示，而用户注册、发表信息等则采用单一入口。因为对于网站拥有者来说，新闻列表、新闻显示页面才是需要搜索引擎关注的高价值目标，而用户注册页面等交互 性功能则根本没有收录的价值。</p>
<p>有朋友提到单一入口的应用程序会有很长一串参数，那么我们分析一下下面这个 url：<br />
index.php?url=news&amp;news_id=123&amp;page=2&amp;sort=title<br />
如果改为直接访问 news.php，也只不过省掉了 url=news 这一个参数而已。</p>
<p>所以认为单一入口的应用程序 url 太复杂是没有道理的。</p>
<p><strong>如何组织单一入口应用程序的功能代码？</strong></p>
<p>单一入口应用程序最大的挑战来自于如何合理组织各个功能的处理代码。但只要遵循一定的步骤，也可以轻松的解决掉这个难题。</p>
<p>首先，对于应用程序的功能要做出一个合理的分解。例如后台的新闻栏目可能包含“添加新闻”、“编辑新闻”、“删除新闻”等多个功能。这时我们就可以将这一组逻辑上关联的功能组合到一个功能模块中，称为“新闻管理”模块。<br />
按照上面的方法整理完应用程序的功能，我们就会得到多个功能模块，而每个模块又是由多个功能组成。（实际上，即便不是单一入口应用程序，功能的整理也是必须的步骤。）</p>
<p>整理完功能后，我们就需要确定如何存放各个功能的代码。这里我推荐两种方式：</p>
<p>1、每个功能模块一个子目录，目录里的每一个文件就是一个功能的实现代码。<br />
这种方式的好处是每个功能的代码都互相隔离，非常便于多人协作。缺点是每个功能之间共享代码和数据不那么方便。例如新闻管理模块中的所有功能都需要一个 “取出新闻栏目记录”的功能，那么采用这种多个独立文件的组织方式，“取出新闻栏目记录”就只能写在另一个文件中，然后由需要该功能的文件include 进去。</p>
<p>2、每个模块一个文件，模块中的每个功能写成一个函数或者一个类方法。<br />
好处不用多说了，非常便于共享代码和数据。缺点就是如果几个人同时改，容易发生冲突。不过借助版本控制软件和差异比较合并工具，冲突还是很容易解决的。</p>
<p>好了，我们的功能代码都确定存放方式了。那么如何调用呢？</p>
<p><strong>index.php 如何调用功能代码？</strong></p>
<p>调用首先就是要设计一个规则，然后让 index.php 根据这个规则来搜索和调用功能代码。就我自己来说，我总是使用 $_GET['url'] 来指定要调用的功能模块，而 $_GET['action'] 来指定该模块的特定功能。因此我的应用程序会使用如下的 url 地址：<br />
index.php?url=news&amp;action=edit</p>
<p>觉得两个参数太多了？那可以使用 index.php?func=news.edit 这样的 url。只需要将 news.edit 拆开为 news 和 edit 就行了。</p>
<p>“嘿嘿，那我故意搞一个 index.php?url=news&amp;action=xxx，看你的应用程序还能运行？”<br />
很显然，这样的 url 只会使得 index.php 无法找到需要的功能代码，最后报告错误。但是这和你在浏览器中访问 newsxxx.php 这个并不存在的文件有什么本质区别呢？</p>
<p>相反，我还可以让 index.php 在发现找不到需要的功能代码时显示一个漂亮的出错页面，并提供一个返回网站首页的连接。</p>
<p>在实际开发中，我倾向于将一些基本服务从应用程序中抽取出来，形成一个应用程序框架。这个框架通常会包含一个 Dispatcher、基本的数据库访问服务、模版引擎、常用的辅助功能等。由于有了一个框架，所以我可以更加让 Dispatcher 更加灵活。例如可以对某些功能模块应用权限检查，而另一些则不检查。</p>
<p><strong>进一步了解单一入口应用程序</strong></p>
<p>要深刻理解一个事物，自己尝试一下是最好的办法。</p>
<p>你可以选择自己实现一个 Dispatcher 以及相应的各种规则，或者选择一个现有的应用程序框架。但更好的方式还是首先尝试一下现有的框架，然后再自己尝试实现一个类似的。这样可以在最短的时间内获得最多的收获。</p>
<p>目前绝大多数 php 应用程序框架都是单一入口的，并采用了 MVC 模式（很遗憾，由于 MVC 实在太复杂，并且和单一入口应用程序也没有必然联系，所以我就不赘述了。感兴趣的朋友可以 google 一下相关资料）。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/php-sigle-inter.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>时间是均匀线性的吗</title>
		<link>http://www.phpboke.com/thetime.html</link>
		<comments>http://www.phpboke.com/thetime.html#comments</comments>
		<pubDate>Thu, 01 Mar 2012 10:11:40 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[心情随笔]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=817</guid>
		<description><![CDATA[2012年，感觉每天上班时间都过得特别快，一转眼一星期，明明已经星期三了，可是感觉好像昨天过的周末，感觉时间过得真快。突然发现小时候和现在对时间的感觉视乎完全不一样。小时候总觉得时间很漫长，每天都盼着放假。而现在却发现时间太快，都希望它能够慢一点，再慢一点。看来不同阶段，对相同时间长度的感觉是真的不一样哦。
]]></description>
			<content:encoded><![CDATA[<p>2012年，感觉每天上班时间都过得特别快，一转眼一星期，明明已经星期三了，可是感觉好像昨天过的周末，感觉时间过得真快。突然发现小时候和现在对时间的感觉视乎完全不一样。小时候总觉得时间很漫长，每天都盼着放假。而现在却发现时间太快，都希望它能够慢一点，再慢一点。看来不同阶段，对相同时间长度的感觉是真的不一样哦。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/thetime.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>金牛座</title>
		<link>http://www.phpboke.com/taurus.html</link>
		<comments>http://www.phpboke.com/taurus.html#comments</comments>
		<pubDate>Wed, 29 Feb 2012 09:09:15 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[心情随笔]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=813</guid>
		<description><![CDATA[春天出生的生辰星位或太阳在金牛座的人的特点： 
继充满激情的牧羊座之后，是不轻易浪费自己能量的金牛座。金牛座的人不愿意毫无意义地说教，无缘无故地行动和失去理智激动。你不放任激情，也没 有紧迫感，这是一个强烈抑制精神和思想总是按一定尺度运行的人。如果出生时刻的天宫图中有较强的金牛座的影响，那么你会有良好的自卫本能。从积极的意义上看，你的性格平稳、有毅力和耐力，勤劳智慧，富有实干精神。为人处世小心谨慎，感情真诚专一。此外，你有极其敏锐的感官，内心怀 有各种欲望。喜欢舒适的生活环境，大自然的壮丽景色、花草和动物。
金牛座的人是一个喜欢按自己的人生哲学走路的人。你不轻易改变自己的生活习惯。固执已见是你性格上的突出特点，同时也是你的主要缺点。平时温文 尔雅，一旦受到触怒，你会变得令人望而生畏。金牛座的人家庭观念较强，你把家庭天地作为寄托自己幸福和安居乐业生活的可靠圣殿。你爱孩子胜过一切，并对你 们寄予厚望。
这一座的人对逆境的适应较慢。挫折和失败常能使你意志消沉，甚至你会人为地把自己囚禁在无声的愤怒之中，拒绝与外界的一切接触。一旦境况有所好 转，你又会重新振作起来，以空前的工作热情去实现自己的目标。金牛座的人思想趋于保守，但善于理财。当你拥有一定数量的财产，手头从不短缺时，你方能感到 坦然自若。经济上，你的现实感非常强，十分善于安排自己的物质和家庭生活。事业上，你也是强者，具有天生的无懈可击的才华。你的成功之路往往是漫长的，但 又是确定无疑的，尤其在农业、建筑和商业等行业方面。

金牛座的男性
这是一个喜欢安定的生活和具有田园诗盘性格的人。感情节奏的变化比较缓慢，然而一经触发将会身不由已，无法自拔。稳定而持久的生活环境，对你至 关重要。你不喜欢素不相识或萍水相逢的人来扰乱你的生活。无论在爱情上，还是在物质上的追求，你都是以可靠和安全作为权衡的主要标准，这甚至是你性格和思 想的基础。
你既是一个多思多虑的人，又是一个不拒绝享乐的人。美味佳肴是你生活中必不可少的伴侣。
对待婚姻，金牛座的人首先考虑的是，这种结合是否对诸方都有利，喜欢根据对方的家境及其工作能力作为选择的主要条件。因为你需要的是一个既能承 担家庭生活的责任，又能帮你料理财政的妻子。你希望美好的爱情中充满佳肴的芳香。你十分欣赏能烧一手好菜的妻子。和谐的爱情生活是你们感情的基础，生理上 的平衡在你的生活中占有极其重要的地位。金牛座的人，对新生事物适应较慢，不愿意轻易改变自己的生活习惯。
家庭和孩子是你生活的中心，是你欢乐和自豪的资本。尤其孩子是你终生夙愿的寄托。
金牛座的人的性格比较平稳，很少发脾气。不过，一旦发作则非同小可，会使人毛骨悚然。
与生辰星位在天蝎座的女性会情投意合，但这两个个性很强的人又不常相逢。
与生辰星位在处女座或魔羯座的女性结为伴侣，生活会充实、和谐和友爱。因为这两个星座的女性在体贴丈夫、管理家务和照顾子女方面各有所长。
总而言之，金牛座的你：
注重现实的金牛座的人说：&#8221;我具有……&#8221;。
表达爱情的方式：忠心耿耿或不厌其烦。
是一个：感情丰富的人。
渴望：感情缠绵和擅长烹任的爱人。
受骗：当受到性爱吸引时。
喜欢：到农村和田野中去。
追求：具有可靠基础的一切。
弱点：自我意识过强。
有利条件：坚持不懈。
不利条件：不爱动。
假期生活：园艺和烹调。
开支：购买起居设备和娱乐用品。
吉祥物：圣甲虫像。
吉祥金属：铜。
吉祥宝石：珊瑚。
吉祥日：星期五。
吉祥数字：6、15、24、33。
喜欢的场所：田园生活、草坪、原野和牧场，银行和保险公司。
吉祥植物：牡丹、锦葵、报春、紫罗兰和野花。
居住条件：绝对舒适的环境，经久耐用的家具和现代化的厨房设备。
理想旅居国：爱尔兰、丹麦、澳大利亚和阿根廷。
]]></description>
			<content:encoded><![CDATA[<p><span style="color: #0000ff;">春天出生的生辰星位或太阳在金牛座的人的特点： </span></p>
<p><span style="color: #0000ff;">继充满激情的牧羊座之后，是不轻易浪费自己能量的金牛座。金牛座的人不愿意毫无意义地说教，无缘无故地行动和失去理智激动。你不放任激情，也没 有紧迫感，这是一个强烈抑制精神和思想总是按一定尺度运行的人。如果出生时刻的天宫图中有较强的金牛座的影响，那么你会有良好的自卫本能。从积极的意义上看，你的性格平稳、有毅力和耐力，勤劳智慧，富有实干精神。为人处世小心谨慎，感情真诚专一。此外，你有极其敏锐的感官，内心怀 有各种欲望。喜欢舒适的生活环境，大自然的壮丽景色、花草和动物。</span></p>
<p><span style="color: #0000ff;">金牛座的人是一个喜欢按自己的人生哲学走路的人。你不轻易改变自己的生活习惯。固执已见是你性格上的突出特点，同时也是你的主要缺点。平时温文 尔雅，一旦受到触怒，你会变得令人望而生畏。金牛座的人家庭观念较强，你把家庭天地作为寄托自己幸福和安居乐业生活的可靠圣殿。你爱孩子胜过一切，并对你 们寄予厚望。<span id="more-813"></span></span></p>
<p><span style="color: #0000ff;">这一座的人对逆境的适应较慢。挫折和失败常能使你意志消沉，甚至你会人为地把自己囚禁在无声的愤怒之中，拒绝与外界的一切接触。一旦境况有所好 转，你又会重新振作起来，以空前的工作热情去实现自己的目标。金牛座的人思想趋于保守，但善于理财。当你拥有一定数量的财产，手头从不短缺时，你方能感到 坦然自若。经济上，你的现实感非常强，十分善于安排自己的物质和家庭生活。事业上，你也是强者，具有天生的无懈可击的才华。你的成功之路往往是漫长的，但 又是确定无疑的，尤其在农业、建筑和商业等行业方面。</span></p>
<p><span style="color: #0000ff;"><a name="jnnan" href="http://astro.sina.com.cn/jian/51.shtml#jnnan"></a></span></p>
<p><span style="color: #0000ff;">金牛座的男性</span></p>
<p><span style="color: #0000ff;">这是一个喜欢安定的生活和具有田园诗盘性格的人。感情节奏的变化比较缓慢，然而一经触发将会身不由已，无法自拔。稳定而持久的生活环境，对你至 关重要。你不喜欢素不相识或萍水相逢的人来扰乱你的生活。无论在爱情上，还是在物质上的追求，你都是以可靠和安全作为权衡的主要标准，这甚至是你性格和思 想的基础。</span></p>
<p><span style="color: #0000ff;">你既是一个多思多虑的人，又是一个不拒绝享乐的人。美味佳肴是你生活中必不可少的伴侣。</span></p>
<p><span style="color: #0000ff;">对待婚姻，金牛座的人首先考虑的是，这种结合是否对诸方都有利，喜欢根据对方的家境及其工作能力作为选择的主要条件。因为你需要的是一个既能承 担家庭生活的责任，又能帮你料理财政的妻子。你希望美好的爱情中充满佳肴的芳香。你十分欣赏能烧一手好菜的妻子。和谐的爱情生活是你们感情的基础，生理上 的平衡在你的生活中占有极其重要的地位。金牛座的人，对新生事物适应较慢，不愿意轻易改变自己的生活习惯。</span></p>
<p><span style="color: #0000ff;">家庭和孩子是你生活的中心，是你欢乐和自豪的资本。尤其孩子是你终生夙愿的寄托。</span></p>
<p><span style="color: #0000ff;">金牛座的人的性格比较平稳，很少发脾气。不过，一旦发作则非同小可，会使人毛骨悚然。</span></p>
<p><span style="color: #0000ff;">与生辰星位在天蝎座的女性会情投意合，但这两个个性很强的人又不常相逢。</span></p>
<p><span style="color: #0000ff;">与生辰星位在处女座或魔羯座的女性结为伴侣，生活会充实、和谐和友爱。因为这两个星座的女性在体贴丈夫、管理家务和照顾子女方面各有所长。</span></p>
<p>总而言之，金牛座的你：</p>
<p>注重现实的金牛座的人说：&#8221;我具有……&#8221;。</p>
<p>表达爱情的方式：忠心耿耿或不厌其烦。</p>
<p>是一个：感情丰富的人。</p>
<p>渴望：感情缠绵和擅长烹任的爱人。</p>
<p>受骗：当受到性爱吸引时。</p>
<p>喜欢：到农村和田野中去。</p>
<p>追求：具有可靠基础的一切。</p>
<p>弱点：自我意识过强。</p>
<p>有利条件：坚持不懈。</p>
<p>不利条件：不爱动。</p>
<p>假期生活：园艺和烹调。</p>
<p>开支：购买起居设备和娱乐用品。</p>
<p>吉祥物：圣甲虫像。</p>
<p>吉祥金属：铜。</p>
<p>吉祥宝石：珊瑚。</p>
<p>吉祥日：星期五。</p>
<p>吉祥数字：6、15、24、33。</p>
<p>喜欢的场所：田园生活、草坪、原野和牧场，银行和保险公司。</p>
<p>吉祥植物：牡丹、锦葵、报春、紫罗兰和野花。</p>
<p>居住条件：绝对舒适的环境，经久耐用的家具和现代化的厨房设备。</p>
<p>理想旅居国：爱尔兰、丹麦、澳大利亚和阿根廷。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/taurus.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>怎样把自己培养成为一个优秀的程序员</title>
		<link>http://www.phpboke.com/good-programmers.html</link>
		<comments>http://www.phpboke.com/good-programmers.html#comments</comments>
		<pubDate>Tue, 28 Feb 2012 09:31:48 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[程序员]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=810</guid>
		<description><![CDATA[



态度篇
1. 做实事：不要抱怨，发牢骚，指责他人，找出问题所在，想办法解决。对问题和错误，要勇于承担。
2. 欲速则不达：用小聪明、权宜之计解决问题，求快而不顾代码质量，会给项目留下要命的死角。
3. 对事不对人：就事论事，明智、真诚、虚心地讨论问题，提出创新方案。
4. 排除万难，奋勇前进：勇气往往是克服困难的唯一方法。
学习篇
5. 跟踪变化：新技术层出不穷并不可怕。坚持学习新技术，读书，读技术杂志，参加技术活动，与人交流。要多理解新词背后的所以然，把握技术大趋势，将新技术用 于产品开发要谨慎。
6. 对团队投资：打造学习型团队，不断提高兄弟们的平均水平。
7. 懂得丢弃：老的套路和技术，该丢，就得丢。不要固步自封。
8. 打破砂锅问到底：不断追问，真正搞懂问题的本质。为什么？应该成为你的口头禅。
9. 把握开发节奏：控制好时间，养成好习惯，不要加班。
开发流程篇
10. 让客户做决定：让用户在现场，倾听他们的声音，对业务最重要的决策应该让他们说了算。
11. 让设计指导而不是操纵开发：设计是前进的地图，它指引的是方向，而不是目的本身。设计的详略程度应该适当。
12. 合理地使用技术：根据需要而不是其他因素选择技术。对各种技术方案进行严格地追问，真诚面对各种问题。
13. 让应用随时都可以发布：通过善用持续集成和版本管理，你应该随时都能够编译、运行甚至部署应用。
14. 提早集成，频繁集成：集成有风险，要尽早尽量多地集成。
15. 提早实现自动化部署
16. 使用演示获得频繁反馈
17. 使用短迭代，增量发布
18. 固定价格就意味着背叛承诺：估算应该基于实际的工作不断变化。
用户篇
19. 守护天使：自动化单元测试是你的守护天使。
20. 先用它再实现它：测试驱动开发其实是一种设计工具。
21. 不同环境，就有不同问题：要重视多平台问题。
22. 自动验收测试
23. 度量真实的进度：在工作量估算上，不要自欺欺人。
24. 倾听用户的声音：每一声抱怨都隐藏着宝贵的真理。
编程篇
25. 代码要清晰地表达意图：代码是给人读的，不要耍小聪明。
26. 用代码沟通：注释的艺术。
27. 动态地进行取舍：记住，没有最佳解决方案。各种目标不可能面面俱到，关注对用户重要的需求。
28. 增量式编程：写一点代码就构建、测试、重构、休息。让代码干净利落。
29. 尽量简单：宁简勿繁。如果没有充足的理由，就不要使用什么模式、原则和特别的技术。
30. 编写内聚的代码：类和组件应该足够小，任务单一。
31. 告知，不要询问：多用消息传递，少用函数调用。
32. 根据契约进行替换：委托往往优于继承。
调试篇
33. 记录问题解决日志：不要在同一地方摔倒两次。错误是最宝贵的财富。
34. 警告就是错误：忽视编译器的警告可能铸成大错。
35. 对问题各个击破：分而治之是计算机科学中最重要的思想之一。但是，要从设计和原型阶段就考虑各部分应该能够很好地分离。
36. 报告所有的异常
37. 提供有用的错误信息：稍微多花一点心思，出错的时候，将给你带来极大便利。
团队协作篇
38. 定期安排会面时间：常开会，开短会。
39. 架构师必须写代码：不写代码的架构师不是好架构师。好的设计都来自实际编程。编程可以带来深入的理解。
40. 实行代码集体所有制：让开发人员在系统不同区域中不同的模块和任务之间轮岗。
41. 成为指导者：教学相长。分享能提高团队的总体能力。
42. 让大家自己想办法：指引方向，而不是直接提供解决方案。让每个人都有机会在干中学习。
43. 准备好后再共享代码：不要提交无法编译或者没有通过单元测试的代码！
44. 做代码复查：复查对提高代码质量、减少错误极为重要。
45. 及时通报进展与问题：主动通报，不要让别人来问你。




]]></description>
			<content:encoded><![CDATA[<div>
<div>
<div>
<div>
<p><strong>态度篇</strong></p>
<p>1. 做实事：不要抱怨，发牢骚，指责他人，找出问题所在，想办法解决。对问题和错误，要勇于承担。</p>
<p>2. 欲速则不达：用小聪明、权宜之计解决问题，求快而不顾代码质量，会给项目留下要命的死角。</p>
<p>3. 对事不对人：就事论事，明智、真诚、虚心地讨论问题，提出创新方案。</p>
<p>4. 排除万难，奋勇前进：勇气往往是克服困难的唯一方法。<span id="more-810"></span></p>
<p><strong>学习篇</strong></p>
<p>5. 跟踪变化：新技术层出不穷并不可怕。坚持学习新技术，读书，读技术杂志，参加技术活动，与人交流。要多理解新词背后的所以然，把握技术大趋势，将新技术用 于产品开发要谨慎。</p>
<p>6. 对团队投资：打造学习型团队，不断提高兄弟们的平均水平。</p>
<p>7. 懂得丢弃：老的套路和技术，该丢，就得丢。不要固步自封。</p>
<p>8. 打破砂锅问到底：不断追问，真正搞懂问题的本质。为什么？应该成为你的口头禅。</p>
<p>9. 把握开发节奏：控制好时间，养成好习惯，不要加班。</p>
<p><strong>开发流程篇</strong></p>
<p>10. 让客户做决定：让用户在现场，倾听他们的声音，对业务最重要的决策应该让他们说了算。</p>
<p>11. 让设计指导而不是操纵开发：设计是前进的地图，它指引的是方向，而不是目的本身。设计的详略程度应该适当。</p>
<p>12. 合理地使用技术：根据需要而不是其他因素选择技术。对各种技术方案进行严格地追问，真诚面对各种问题。</p>
<p>13. 让应用随时都可以发布：通过善用持续集成和版本管理，你应该随时都能够编译、运行甚至部署应用。</p>
<p>14. 提早集成，频繁集成：集成有风险，要尽早尽量多地集成。</p>
<p>15. 提早实现自动化部署</p>
<p>16. 使用演示获得频繁反馈</p>
<p>17. 使用短迭代，增量发布</p>
<p>18. 固定价格就意味着背叛承诺：估算应该基于实际的工作不断变化。</p>
<p><strong>用户篇</strong></p>
<p>19. 守护天使：自动化单元测试是你的守护天使。</p>
<p>20. 先用它再实现它：测试驱动开发其实是一种设计工具。</p>
<p>21. 不同环境，就有不同问题：要重视多平台问题。</p>
<p>22. 自动验收测试</p>
<p>23. 度量真实的进度：在工作量估算上，不要自欺欺人。</p>
<p>24. 倾听用户的声音：每一声抱怨都隐藏着宝贵的真理。</p>
<p><strong>编程篇</strong></p>
<p>25. 代码要清晰地表达意图：代码是给人读的，不要耍小聪明。</p>
<p>26. 用代码沟通：注释的艺术。</p>
<p>27. 动态地进行取舍：记住，没有最佳解决方案。各种目标不可能面面俱到，关注对用户重要的需求。</p>
<p>28. 增量式编程：写一点代码就构建、测试、重构、休息。让代码干净利落。</p>
<p>29. 尽量简单：宁简勿繁。如果没有充足的理由，就不要使用什么模式、原则和特别的技术。</p>
<p>30. 编写内聚的代码：类和组件应该足够小，任务单一。</p>
<p>31. 告知，不要询问：多用消息传递，少用函数调用。</p>
<p>32. 根据契约进行替换：委托往往优于继承。</p>
<p><strong>调试篇</strong></p>
<p>33. 记录问题解决日志：不要在同一地方摔倒两次。错误是最宝贵的财富。</p>
<p>34. 警告就是错误：忽视编译器的警告可能铸成大错。</p>
<p>35. 对问题各个击破：分而治之是计算机科学中最重要的思想之一。但是，要从设计和原型阶段就考虑各部分应该能够很好地分离。</p>
<p>36. 报告所有的异常</p>
<p>37. 提供有用的错误信息：稍微多花一点心思，出错的时候，将给你带来极大便利。</p>
<p><strong>团队协作篇</strong></p>
<p>38. 定期安排会面时间：常开会，开短会。</p>
<p>39. 架构师必须写代码：不写代码的架构师不是好架构师。好的设计都来自实际编程。编程可以带来深入的理解。</p>
<p>40. 实行代码集体所有制：让开发人员在系统不同区域中不同的模块和任务之间轮岗。</p>
<p>41. 成为指导者：教学相长。分享能提高团队的总体能力。</p>
<p>42. 让大家自己想办法：指引方向，而不是直接提供解决方案。让每个人都有机会在干中学习。</p>
<p>43. 准备好后再共享代码：不要提交无法编译或者没有通过单元测试的代码！</p>
<p>44. 做代码复查：复查对提高代码质量、减少错误极为重要。</p>
<p>45. 及时通报进展与问题：主动通报，不要让别人来问你。</p>
</div>
</div>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/good-programmers.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在 PHP 中养成 7 个面向对象的好习惯</title>
		<link>http://www.phpboke.com/%e5%9c%a8-php-%e4%b8%ad%e5%85%bb%e6%88%90-7-%e4%b8%aa%e9%9d%a2%e5%90%91%e5%af%b9%e8%b1%a1%e7%9a%84%e5%a5%bd%e4%b9%a0%e6%83%af.html</link>
		<comments>http://www.phpboke.com/%e5%9c%a8-php-%e4%b8%ad%e5%85%bb%e6%88%90-7-%e4%b8%aa%e9%9d%a2%e5%90%91%e5%af%b9%e8%b1%a1%e7%9a%84%e5%a5%bd%e4%b9%a0%e6%83%af.html#comments</comments>
		<pubDate>Tue, 28 Feb 2012 08:43:59 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[PHP高级开发]]></category>
		<category><![CDATA[程序员]]></category>
		<category><![CDATA[php学习]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=807</guid>
		<description><![CDATA[在 PHP 编程早期，PHP 代码在本质上是限于面向过程的。过程代码 的特征在于使用过程构建应用程序块。过程通过允许过程之间的调用提供某种程度的重用。
但是，没有面向对象的语言构造，程序员仍然可以把 OO 特性引入到 PHP 代码中。这样做有点困难并且会使代码难于阅读，因为它是混合范例（含有伪 OO 设计的过程语言）。使用 PHP 代码中的 OO 构造 — 例如能够定义和使用类、能够构建使用继承的类之间的关系以及能够定义接口 — 可以更轻松地构建符合优秀 OO 实践的代码。
虽然没有过多模块化的纯过程设计运行得很好，但是 OO 设计的优点表现在维护上。由于典型应用程序的大部分生命周期都花费在维护上，因此代码维护是应用程序生命周期的重要部分。并且在开发过程中代码维护很容易 被遗忘。如果在应用程序开发和部署方面存在竞争，那么长期可维护性可能被放在比较次要的地位。
模块化 — 优秀 OO 设计的主要特性之一 — 可以帮助完成这样的维护。模块化将帮助封装更改，这样可以随着时间的推移更轻松地扩展和修改应用程序。
总的来说，虽然构建 OO 软件的习惯不止 7 个，但是遵循这里的 7 个习惯可以使代码符合基本 OO 设计标准。它们将为您提供更牢固的基础，在此基础之上建立更多 OO 习惯并构建可轻松维护与扩展的软件。这些习惯针对模块化的几个主要特性。有关独立于语言的 OO 设计优点的更多信息，请参阅 参考资料。
7 个优秀 PHP OO 习惯包括：

保持谦虚。
做个好邻居。
避免看到美杜莎。
利用最弱的链接。
您是橡皮；我是胶水。
限制传播。
考虑使用模式。

保持谦虚
保持谦虚指避免在类实现和函数实现中暴露自己。隐藏您的信息是一项基本习惯。如果不能养成隐藏实现细节的习惯，那么将很难养成任何其他习惯。信息隐藏也称为封装。
直接公开公共字段是一个坏习惯的原因有很多，最重要的原因是让您在实现更改中没有应有的选择。使用 OO 概念隔离更改，而封装在确保所作更改在本质上不是病毒性（viral）更改方面扮演不可或缺的角色。病毒性 更改是开始时很小的更改 — 如将保存三个元素的数组更改为一个只包含两个元素的数组。突然，您发现需要更改越来越多的代码以适应本应十分微不足道的更改。
开始隐藏信息的一种简单方法是保持字段私有并且用公共访问方法公开这些字段，就像家中的窗户一样。并没有让整面墙都朝外部开放，而只打开一两扇窗户（我将在 “好习惯：使用公共访问方法” 中介绍访问方法的更多信息）。
除了允许您的实现隐藏在更改之后外，使用公共访问方法而非直接公开字段将允许您在基本实现的基础上进行构建，方法为覆盖访问方法的实现以执行略微不同于父方法的行为。它还允许您构建一个抽象实现，从而使实际实现委托给覆盖基本实现的类。
坏习惯：公开公共字段
在清单 1 [...]]]></description>
			<content:encoded><![CDATA[<p>在 PHP 编程早期，PHP 代码在本质上是限于面向过程的。<em>过程代码</em> 的特征在于使用过程构建应用程序块。过程通过允许过程之间的调用提供某种程度的重用。</p>
<p>但是，没有面向对象的语言构造，程序员仍然可以把 OO 特性引入到 PHP 代码中。这样做有点困难并且会使代码难于阅读，因为它是混合范例（含有伪 OO 设计的过程语言）。使用 PHP 代码中的 OO 构造 — 例如能够定义和使用类、能够构建使用继承的类之间的关系以及能够定义接口 — 可以更轻松地构建符合优秀 OO 实践的代码。</p>
<p>虽然没有过多模块化的纯过程设计运行得很好，但是 OO 设计的优点表现在维护上。由于典型应用程序的大部分生命周期都花费在维护上，因此代码维护是应用程序生命周期的重要部分。并且在开发过程中代码维护很容易 被遗忘。如果在应用程序开发和部署方面存在竞争，那么长期可维护性可能被放在比较次要的地位。</p>
<p><em>模块化</em> — 优秀 OO 设计的主要特性之一 — 可以帮助完成这样的维护。模块化将帮助封装更改，这样可以随着时间的推移更轻松地扩展和修改应用程序。</p>
<p>总的来说，虽然构建 OO 软件的习惯不止 7 个，但是遵循这里的 7 个习惯可以使代码符合基本 OO 设计标准。它们将为您提供更牢固的基础，在此基础之上建立更多 OO 习惯并构建可轻松维护与扩展的软件。这些习惯针对模块化的几个主要特性。有关独立于语言的 OO 设计优点的更多信息，请参阅 <a href="http://www.ibm.com/developerworks/cn/opensource/os-php-7oohabits/?ca=drs-tp4408#resources">参考资料</a>。</p>
<p>7 个优秀 PHP OO 习惯包括：</p>
<ol>
<li>保持谦虚。</li>
<li>做个好邻居。</li>
<li>避免看到美杜莎。</li>
<li>利用最弱的链接。</li>
<li>您是橡皮；我是胶水。</li>
<li>限制传播。</li>
<li>考虑使用模式。<span id="more-807"></span></li>
</ol>
<p><a name="bemodest">保持谦虚</a></p>
<p>保持谦虚指避免在类实现和函数实现中暴露自己。隐藏您的信息是一项基本习惯。如果不能养成隐藏实现细节的习惯，那么将很难养成任何其他习惯。信息隐藏也称为<em>封装</em>。</p>
<p>直接公开公共字段是一个坏习惯的原因有很多，最重要的原因是让您在实现更改中没有应有的选择。使用 OO 概念隔离更改，而封装在确保所作更改在本质上不是病毒性（viral）更改方面扮演不可或缺的角色。<em>病毒性</em> 更改是开始时很小的更改 — 如将保存三个元素的数组更改为一个只包含两个元素的数组。突然，您发现需要更改越来越多的代码以适应本应十分微不足道的更改。</p>
<p>开始隐藏信息的一种简单方法是保持字段私有并且用公共访问方法公开这些字段，就像家中的窗户一样。并没有让整面墙都朝外部开放，而只打开一两扇窗户（我将在 “<a href="http://www.ibm.com/developerworks/cn/opensource/os-php-7oohabits/?ca=drs-tp4408#publicaccessor">好习惯：使用公共访问方法</a>” 中介绍访问方法的更多信息）。</p>
<p>除了允许您的实现隐藏在更改之后外，使用公共访问方法而非直接公开字段将允许您在基本实现的基础上进行构建，方法为覆盖访问方法的实现以执行略微不同于父方法的行为。它还允许您构建一个抽象实现，从而使实际实现委托给覆盖基本实现的类。</p>
<p><a name="exposefield">坏习惯：公开公共字段</a></p>
<p>在清单 1 的坏代码示例中，<code>Person</code> 对象的字段被直接公开为公共字段而非使用访问方法。虽然此行为十分诱人，尤其对于轻量级数据对象来说更是如此，但是它将对您提出限制。<br />
<a name="listing1"><strong>清单 1. 公开公共字段的坏习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
class Person
{
    public $prefix;
    public $givenName;
    public $familyName;
    public $suffix;
}

$person = new Person();
$person-&gt;prefix = "Mr.";
$person-&gt;givenName = "John";

echo($person-&gt;prefix);
echo($person-&gt;givenName);

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p>如果对象有任何更改，则使用该对象的所有代码也都需要更改。例如，如果某人的教名、姓氏和其他名字被封装到 <code>PersonName</code> 对象中，则需要修改所有代码以适应更改。</p>
<p><a name="publicaccessor">好习惯：使用公共访问方法</a></p>
<p>通过使用优秀的 OO 习惯（参见清单 2），同一个对象现在拥有私有字段而非公共字段，并且通过称为<em>访问方法</em> 的 <code>get</code> 和 <code>set</code> 公共方法谨慎地向外界公开私有字段。这些访问方法现在提供了一种从 PHP 类中获取信息的公共方法，这样在实现发生更改时，更改使用类的所有代码的需求很可能变小。<br />
<a name="listing2"><strong>清单 2. 使用公共访问方法的好习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
class Person
{
    private $prefix;
    private $givenName;
    private $familyName;
    private $suffix;

    public function setPrefix($prefix)
    {
        $this-&gt;prefix = $prefix;
    }

    public function getPrefix()
    {
        return $this-&gt;prefix;
    }

    public function setGivenName($gn)
    {
        $this-&gt;givenName = $gn;
    }

    public function getGivenName()
    {
        return $this-&gt;givenName;
    }

    public function setFamilyName($fn)
    {
        $this-&gt;familyName = $fn;
    }

    public function getFamilyName()
    {
        return $this-&gt;familyName;
    }

    public function setSuffix($suffix)
    {
        $this-&gt;suffix = $suffix;
    }

    public function getSuffix()
    {
        return $suffix;
    }

}

$person = new Person();
$person-&gt;setPrefix("Mr.");
$person-&gt;setGivenName("John");

echo($person-&gt;getPrefix());
echo($person-&gt;getGivenName());

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p>乍看之下，这段代码可能会完成大量工作，并且实际上可能更多是在前端的工作。但是，通常，使用优秀的 OO 习惯从长远来看十分划算，因为将极大地巩固未来更改。</p>
<p>在清单 3 中所示的代码版本中，我已经更改了内部实现以使用名称部件的关联数组。比较理想的情况是，我希望拥有错误处理并且更仔细地检查元素是否存在，但是本例的目 的在于展示使用我的类的代码无需更改的程度 — 代码并没有察觉到类发生更改。记住采用 OO 习惯的原因是要谨慎封装更改，这样代码将更具有可扩展性并且更容易维护。<br />
<a name="listing3"><strong>清单 3. 使用不同内部实现的另一个示例</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
class Person
{
    private $personName = array();

    public function setPrefix($prefix)
    {
        $this-&gt;personName['prefix'] = $prefix;
    }

    public function getPrefix()
    {
        return $this-&gt;personName['prefix'];
    }

    public function setGivenName($gn)
    {
        $this-&gt;personName['givenName'] = $gn;
    }

    public function getGivenName()
    {
        return $this-&gt;personName['givenName'];
    }

    /* etc... */
}

/*
 * Even though the internal implementation changed, the code here stays exactly
 * the same. The change has been encapsulated only to the Person class.
 */
$person = new Person();
$person-&gt;setPrefix("Mr.");
$person-&gt;setGivenName("John");

echo($person-&gt;getPrefix());
echo($person-&gt;getGivenName());

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_TgOls1W03k.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" alt="" width="100%" height="4" /></p>
<table border="0" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td></td>
</tr>
<tr>
<td align="right" valign="top"></td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<p><a name="goodneighbor">做个好邻居</a></p>
<p>在构建类时，它应当正确地处理自己的错误。如果该类不知道如何处理错误，则应当以其调用者理解的格式封装这些错误。此外，避免返回空对象或者状态无 效的对象。许多时候，只需通过检验参数并抛出特定异常说明提供参数无效的原因就可以实现这一点。在您养成这个习惯时，它可以帮您 — 和维护代码或使用对象的人员 — 节省很多时间。</p>
<p><a name="noerror">坏习惯：不处理错误</a></p>
<p>考虑清单 4 中所示的示例，该示例将接受一些参数并返回填充了一些值的 <code>Person</code> 对象。但是，在 <code>parsePersonName()</code> 方法中，没有验证提供的 <code>$val</code> 变量是否为空、是否是零长度字符串或者字符串是否使用无法解析的格式。<code>parsePersonName()</code> 方法不返回 <code>Person</code> 对象，但是返回 null。使用这种方法的管理员或程序员可能会觉得很麻烦 — 至少他们现在需要开始设置断点并调试 PHP 脚本。<br />
<a name="listing4"><strong>清单 4. 不抛出或处理错误的坏习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>class PersonUtils
{
    public static function parsePersonName($format, $val)
    {
        if (strpos(",", $val) &gt; 0) {
            $person = new Person();
            $parts = split(",", $val); // Assume the value is last, first
            $person-&gt;setGivenName($parts[1]);
            $person-&gt;setFamilyName($parts[0]);
        }
        return $person;
    }
}
</pre>
</td>
</tr>
</tbody>
</table>
<p>清单 4 中的 <code>parsePersonName()</code> 方法可以修改为在 <code>if</code> 条件外部初始化 <code>Person</code> 对象，确保总是获得有效的 <code>Person</code> 对象。但是，您得到的是没有 set 属性的 <code>Person</code>，这仍然没有很好地改善您的困境。</p>
<p><a name="ownerrors">好习惯：每个模块都处理自己的错误</a></p>
<p>不要让调用方凭空猜测，而是对参数进行预先验证。如果未设置的变量无法生成有效的结果，请检查变量并抛出 <code>InvalidArgumentException</code>。如果字符串不能为空或者必须为特定格式，请检查格式并抛出异常。清单 5 解释了如何在演示一些基本验证的 <code>parsePerson()</code> 方法中创建异常以及一些新条件。<br />
<a name="listing5"><strong>清单 5. 抛出错误的好习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
class InvalidPersonNameFormatException extends LogicException {}

class PersonUtils
{
    public static function parsePersonName($format, $val)
    {
        if (! $format) {
            throw new InvalidPersonNameFormatException("Invalid PersonName format.");
        }

        if ((! isset($val)) || strlen($val) == 0) {
            throw new InvalidArgumentException("Must supply a non-null value to parse.");
        }

    }
}
?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p>最终目的是希望人们能够使用您的类，而不必了解其中的工作原理。如果他们使用的方法不正确或者不是按照期望的方法使用，也不需要猜测不能工作的原因。作为一个好邻居，您需要知道对您的类进行重用的人并没有特异功能，因此您需要解决猜测的问题。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_TgOls1W03k.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" alt="" width="100%" height="4" /></td>
</tr>
</tbody>
</table>
<p><a name="medusa">避免看到美杜莎</a></p>
<p>在我最初了解 OO 概念时，我十分怀疑接口是否真正有帮助。我的同事给我打了个比方，说不使用接口就好像看到美杜莎的头。在希腊神话中，美杜莎是长着蛇发的女怪。凡是看了她 一眼的人都会变成石头。杀死美杜莎的珀尔休斯通过在盾上观察她的影子，避免了变成石头而得以与她对抗。</p>
<p>接口就是对付美杜莎的镜子。当您使用一个特定的具体实现时，代码也必须随着实现代码的更改而更改。直接使用实现将限制您的选择，因为您已经在本质上把类变成了 “石头”。</p>
<p><a name="nointerface">坏习惯：不使用接口</a></p>
<p>清单 6 显示了从数据库中装入 <code>Person</code> 对象的示例。它将获取人员的姓名并返回数据库中匹配的 <code>Person</code> 对象。<br />
<a name="listing6"><strong>清单 6. 不使用接口的坏习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
class DBPersonProvider
{
    public function getPerson($givenName, $familyName)
    {
        /* go to the database, get the person... */
        $person = new Person();
        $person-&gt;setPrefix("Mr.");
        $person-&gt;setGivenName("John");
        return $person;
    }
}

/* I need to get person data... */
$provider = new DBPersonProvider();
$person = $provider-&gt;getPerson("John", "Doe");

echo($person-&gt;getPrefix());
echo($person-&gt;getGivenName());

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p>在环境发生更改之前，从数据库中装入 <code>Person</code> 的代码都可以正常运行。例如，从数据库装入 <code>Person</code> 可能适用于第一个版本的应用程序，但是对于第二个版本，可能需要添加从 Web 服务装入人员的功能。其实，该类已经变成 “石头”，因为它在直接使用实现类并且现在能做的更改十分有限。</p>
<p><a name="useinterfaces">好习惯：使用接口</a></p>
<p>清单 7 显示了一个代码示例，在实现了加载用户的新方法后并没有进行更改。该示例显示了一个名为 <code>PersonProvider</code> 的接口，该接口将声明单个方法。如果任何代码使用 <code>PersonProvider</code>，代码都禁止直接使用实现类。相反，它就像是一个实际对象一样使用 <code>PersonProvider</code>。<br />
<a name="listing7"><strong>清单 7. 使用接口的好习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
interface PersonProvider
{
    public function getPerson($givenName, $familyName);
}

class DBPersonProvider implements PersonProvider
{
    public function getPerson($givenName, $familyName)
    {
        /* pretend to go to the database, get the person... */
        $person = new Person();
        $person-&gt;setPrefix("Mr.");
        $person-&gt;setGivenName("John");
        return $person;
    }
}

class PersonProviderFactory
{
    public static function createProvider($type)
    {
        if ($type == 'database')
        {
            return new DBPersonProvider();
        } else {
            return new NullProvider();
        }
    }
}

$config = 'database';
/* I need to get person data... */
$provider = PersonProviderFactory::createProvider($config);
$person = $provider-&gt;getPerson("John", "Doe");

echo($person-&gt;getPrefix());
echo($person-&gt;getGivenName());
?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p>在使用接口时，尝试避免直接引用实现类。相反，使用对象外部的内容可以提供正确的实现。如果您的类将装入基于某些逻辑的实现，它仍然需要获取所有实现类的定义，并且那样做也无法取得任何效果。</p>
<p>您可以使用 Factory 模式来创建实现接口的实现类的实例。根据约定，<code>factory</code> 方法将以 <code>create</code> 为开头并返回接口。它可以为您的 <code>factory</code> 获取必要的参数以计算出应当返回哪个实现类。</p>
<p>在清单 7 中，<code>createProvider()</code> 方法只是获取 <code>$type</code>。如果 <code>$type</code> 被设为 <code>database</code>，工厂将返回 <code>DBPersonProvider</code> 的实例。从数据库中装入人员的任何新实现都不要求在使用工厂和接口的类中进行任何更改。<code>DBPersonProvider</code> 将实现 <code>PersonProvider</code> 接口并且拥有 <code>getPerson()</code> 方法的实际实现。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_TgOls1W03k.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" alt="" width="100%" height="4" /></td>
</tr>
</tbody>
</table>
<p><a name="weakestlink">利用最弱的链接</a></p>
<p>将模块<em>松散耦合</em> 在一起是件好事情；它是允许您封装更改的属性之一。另外两个习惯 — “保持谨慎” 和 “避免看到美杜莎” — 可帮助您构建松散耦合的模块。要实现松散耦合的类，可通过养成降低类依赖关系的习惯实现。</p>
<p><a name="tightcoupling">坏习惯：紧密耦合</a></p>
<p>在清单 8 中，降低依赖关系并不是必须降低使用对象的客户机的依赖关系。相反，该示例将演示如何降低与正确类的依赖关系并最小化这种依赖关系。<br />
<a name="listing8"><strong>清单 8. <code>Address</code> 中紧密耦合的坏习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php

require_once "./AddressFormatters.php";

class Address
{
    private $addressLine1;
    private $addressLine2;
    private $city;
    private $state; // or province...
    private $postalCode;
    private $country;

    public function setAddressLine1($line1)
    {
        $this-&gt;addressLine1 = $line1;
    }

		/* accessors, etc... */

    public function getCountry()
    {
        return $this-&gt;country;
    }

    public function format($type)
    {
        if ($type == "inline") {
            $formatter = new InlineAddressFormatter();
        } else if ($type == "multiline") {
            $formatter = new MultilineAddressFormatter();
        } else {
            $formatter = new NullAddressFormatter();
        }
        return $formatter-&gt;format($this-&gt;getAddressLine1(),
            $this-&gt;getAddressLine2(),
            $this-&gt;getCity(), $this-&gt;getState(), $this-&gt;getPostalCode(),
            $this-&gt;getCountry());
    }
}

$addr = new Address();
$addr-&gt;setAddressLine1("123 Any St.");
$addr-&gt;setAddressLine2("Ste 200");
$addr-&gt;setCity("Anytown");
$addr-&gt;setState("AY");
$addr-&gt;setPostalCode("55555-0000");
$addr-&gt;setCountry("US");

echo($addr-&gt;format("multiline"));
echo("n");

echo($addr-&gt;format("inline"));
echo("n");

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p>在 <code>Address</code> 对象上调用 <code>format()</code> 方法的代码可能看上去很棒 — 这段代码所做的是使用 <code>Address</code> 类，调用 <code>format()</code> 并完成。相反，<code>Address</code> 类就没那么幸运。它需要了解用于正确格式化的各种格式化方法，这可能使 <code>Address</code> 对象无法被其他人很好地重用，尤其是在其他人没有兴趣在 <code>format()</code> 方法中使用格式化方法类的情况下。虽然使用 <code>Address</code> 的代码没有许多依赖关系，但是 <code>Address</code> 类却有大量代码，而它可能只是一个简单的数据对象。</p>
<p><code>Address</code> 类与知道如何格式化 <code>Address</code> 对象的实现类紧密耦合。</p>
<p><a name="loosecoupling">好习惯：在对象之间松散耦合</a></p>
<p>在构建优秀的 OO 设计时，必须考虑称为<em>关注点分离</em>（Separation of Concerns，SoC）的概念。SoC 指尝试通过真正关注的内容分离对象，从而降低耦合度。在最初的 <code>Address</code> 类中，它必须关注如何进行格式化。这可能不是优秀的设计。然而，<code>Address</code> 类应当考虑 <code>Address</code> 的各部分，而某种格式化方法应当关注如何正确格式化地址。</p>
<p>在清单 9 中，格式化地址的代码被移到接口、实现类和工厂中 — 养成 “使用接口” 的习惯。现在，<code>AddressFormatUtils</code> 类负责创建格式化方法并格式化 <code>Address</code>。任何其他对象现在都可以使用 <code>Address</code> 而不必担心要求获得格式化方法的定义。</p>
<p><a name="listing9"><strong>清单 9. 在对象之间松散耦合的好习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php

interface AddressFormatter
{
    public function format($addressLine1, $addressLine2, $city, $state,
        $postalCode, $country);
}

class MultiLineAddressFormatter implements AddressFormatter
{
    public function format($addressLine1, $addressLine2, $city, $state,
        $postalCode, $country)
    {
        return sprintf("%sn%sn%s, %s %sn%s",
            $addressLine1, $addressLine2, $city, $state, $postalCode, $country);
    }
}

class InlineAddressFormatter implements AddressFormatter
{
    public function format($addressLine1, $addressLine2, $city, $state,
        $postalCode, $country)
    {
        return sprintf("%s %s, %s, %s %s %s",
            $addressLine1, $addressLine2, $city, $state, $postalCode, $country);
    }
}

class AddressFormatUtils
{
    public static function formatAddress($type, $address)
    {
        $formatter = AddressFormatUtils::createAddressFormatter($type);

        return $formatter-&gt;format($address-&gt;getAddressLine1(),
            $address-&gt;getAddressLine2(),
            $address-&gt;getCity(), $address-&gt;getState(),
            $address-&gt;getPostalCode(),
            $address-&gt;getCountry());
    }

    private static function createAddressFormatter($type)
    {
        if ($type == "inline") {
            $formatter = new InlineAddressFormatter();
        } else if ($type == "multiline") {
            $formatter = new MultilineAddressFormatter();
        } else {
            $formatter = new NullAddressFormatter();
        }
        return $formatter;
    }
}

$addr = new Address();
$addr-&gt;setAddressLine1("123 Any St.");
$addr-&gt;setAddressLine2("Ste 200");
$addr-&gt;setCity("Anytown");
$addr-&gt;setState("AY");
$addr-&gt;setPostalCode("55555-0000");
$addr-&gt;setCountry("US");

echo(AddressFormatUtils::formatAddress("multiline", $addr));
echo("n");

echo(AddressFormatUtils::formatAddress("inline", $addr));
echo("n");
?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p>当然，缺点是只要使用模式，通常就意味着工件（类、文件）的数量会增加。但是，通过减少每个类中的维护可以弥补这个缺点，甚至在获得正确的可重用性时反而可以减少工件量。</p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_TgOls1W03k.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" alt="" width="100%" height="4" /></td>
</tr>
</tbody>
</table>
<p><a name="rubber">您是橡皮；我是胶水</a></p>
<p>具有高度内聚力的 OO 设计被集中并组织到相关模块中。了解 “关注点” 对于决定如何紧密地联系函数和类十分重要。</p>
<p><a name="lowcohesion">坏习惯：降低内聚力</a></p>
<p>当设计的<em>内聚力较低</em> 时，它就不能良好地组织类和方法。<em>意大利面条式代码（spaghetti code）</em>一词通常用于描述捆绑在一起并且具有低内聚力的类和方法。清单 10 提供了意大利面条式代码的示例。相对通用的 <code>Utils</code> 类将使用许多不同对象并且有许多依赖关系。它执行很多操作，因而很难实现重用。<br />
<a name="listing10"><strong>清单 10. 降低内聚力的坏习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php

class Utils
{
    public static function formatAddress($formatType, $address1,
        $address2, $city, $state)
    {
        return "some address string";
    }

    public static function formatPersonName($formatType, $givenName,
        $familyName)
    {
        return "some person name";
    }

    public static function parseAddress($formatType, $val)
    {
        // real implementation would set values, etc...
        return new Address();
    }

    public static function parseTelephoneNumber($formatType, $val)
    {
        // real implementation would set values, etc...
        return new TelephoneNumber();
    }
}

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p><a name="highcohesion">好习惯：利用高内聚力</a></p>
<p><em>高内聚力</em> 指将相互关联的类和方法分组在一起。如果方法和类都具有高度的内聚力，则可以轻松地分解整个组而不影响设计。具有高内聚力的设计将提供降低耦合的机会。清单 11 显示了被较好组织到类中的两个方法。<code>AddressUtils</code> 类将包含用于处理 <code>Address</code> 类的方法，显示了与地址相关的方法之间的高度内聚力。同样地，<code>PersonUtils</code> 将包含专门处理 <code>Person</code> 对象的方法。这两个拥有高度内聚力方法的新类的耦合性都很低，因为可以完全独立地使用。<br />
<a name="listing11"><strong>清单 11. 高内聚力的好习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php

class AddressUtils
{
    public static function formatAddress($formatType, $address1,
        $address2, $city, $state)
    {
        return "some address string";
    }

    public static function parseAddress($formatType, $val)
    {
        // real implementation would set values, etc...
        return new Address();
    }

}

class PersonUtils
{
    public static function formatPersonName($formatType, $givenName,
        $familyName)
    {
        return "some person name";
    }

    public static function parsePersonName($formatType, $val)
    {
        // real implementation would set values, etc...
        return new PersonName();
    }
}

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_TgOls1W03k.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" alt="" width="100%" height="4" /></td>
</tr>
</tbody>
</table>
<p><a name="keepinfamily">限制传播</a></p>
<p>我经常对我所在的软件团队（我在其中担任技术主管或架构师）的成员提起，OO 语言最大的敌人是复制和粘贴操作。当在缺少预先 OO 设计的情况下使用时，没有任何操作会像在类之间复制代码那样具有破坏性。无论何时，如果想将代码从一个类复制到下一个类中，请停下来并考虑如何使用类层次 结构利用类似功能或相同功能。在大多数情况下，使用优秀设计后，您将会发现完全没有必要复制代码。</p>
<p><a name="nohierarchy">坏习惯：不使用类层次结构</a></p>
<p>清单 12 显示了部分类的简单示例。它们从重复的字段和方法开始 — 从长远来看，不利于应用程序作出更改。如果 <code>Person</code> 类中有缺陷，则 <code>Employee</code> 类中也很可能有一个缺陷，因为看上去似乎实现是在两个类之间复制的。<br />
<a name="listing12"><strong>清单 12. 不使用层次结构的坏习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
class Person
{
    private $givenName;
    private $familyName;
}

class Employee
{
    private $givenName;
    private $familyName;
}

?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<p><em>继承</em> 是一个很难入手的习惯，因为构建正确继承模型的分析通常需要花费大量时间。反过来，使用 <strong>Ctrl+C</strong> 组合键和 <strong>Ctrl+V</strong> 组合键构建新实现只需几秒钟。但是省下的这部分时间通常会在维护阶段迅速抵销掉，因为应用程序实际上将花费大量进行维护。</p>
<p><a name="inheritance">好习惯：利用继承</a></p>
<p>在清单 13 中，新 <code>Employee</code> 类将扩展 <code>Person</code> 类。它现在将继承所有通用方法并且不重新实现这些方法。此外，清单 13 显示了抽象方法的用法，演示如何将基本功能放入基类中以及如何阻止实现类使用特定函数。<br />
<a name="listing13"><strong>清单 13. 利用继承的好习惯</strong></a></p>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td>
<pre>&lt;?php
abstract class Person
{
    private $givenName;
    private $familyName;

    public function setGivenName($gn)
    {
        $this-&gt;givenName = $gn;
    }

    public function getGivenName()
    {
        return $this-&gt;givenName;
    }

    public function setFamilyName($fn)
    {
        $this-&gt;familyName = $fn;
    }

    public function getFamilyName()
    {
        return $this-&gt;familyName;
    }

    public function sayHello()
    {
        echo("Hello, I am ");
        $this-&gt;introduceSelf();
    }

    abstract public function introduceSelf();

}

class Employee extends Person
{
    private $role;

    public function setRole($r)
    {
        $this-&gt;role = $r;
    }

    public function getRole()
    {
        return $this-&gt;role;
    }

    public function introduceSelf()
    {
        echo($this-&gt;getRole() . " " . $this-&gt;getGivenName() . " " .
            $this-&gt;getFamilyName());
    }
}
?&gt;
</pre>
</td>
</tr>
</tbody>
</table>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_TgOls1W03k.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" alt="" width="100%" height="4" /></td>
</tr>
</tbody>
</table>
<p><a name="patterns">考虑使用模式</a></p>
<p>设计模式指对象和方法的常见交互，并且时间证明它可以解决某些问题。当您考虑使用设计模式时，您就需要了解类之间如何进行交互。它是构建类及其交互操作的简单方法，无需重蹈他人的覆辙，并从经过证明的设计中获益。</p>
<p><a name="oneobject">坏习惯：一次考虑一个对象</a></p>
<p>实际上没有适当的代码示例可以演示如何考虑使用模式（尽管有丰富的优秀示例可以显示模式实现）。但是，一般而言，您知道在满足以下条件时一次只能考虑一个对象：</p>
<ul>
<li>不会提前设计对象模型。</li>
<li>开始编写单一方法的实现，而无需去掉大部分模型。</li>
<li>在交谈中不使用设计模式名而宁愿谈论实现。</li>
</ul>
<p><a name="addobjects">好习惯：同时添加模式中形成的对象</a></p>
<p>一般而言，当您在执行以下操作时就是在考虑使用模式：</p>
<ul>
<li>提前构建类及其交互操作。</li>
<li>根据模式套用类。</li>
<li>使用模式名，如 <em>Factory、Singleton</em> 和 <em>Facade</em>。</li>
<li>去掉大部分模型，然后开始添加实现。</li>
</ul>
<table border="0" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_TgOls1W03k.gif" alt="" width="100%" height="1" /><br />
<img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" border="0" alt="" width="8" height="6" /></td>
</tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" align="right">
<tbody>
<tr align="right">
<td><img src="http://www.phpv.net/uploadfile/month_200811/local_NrC5xCThkP.gif" alt="" width="100%" height="4" /></td>
</tr>
</tbody>
</table>
<p><a name="conclusion">结束语</a></p>
<p>在 PHP 中养成良好的 OO 习惯将帮助您构建更稳定、更易于维护和更易于扩展的应用程序。记住：</p>
<ul>
<li>保持谨慎。</li>
<li>做个好邻居。</li>
<li>避免看到美杜莎。</li>
<li>利用最弱的链接。</li>
<li>您是橡皮，我是胶水。</li>
<li>限制传播。</li>
<li>考虑使用模式。</li>
</ul>
<p>当您养成并应用这些习惯后，您很可能会惊讶地发现应用程序在质量上的飞跃。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/%e5%9c%a8-php-%e4%b8%ad%e5%85%bb%e6%88%90-7-%e4%b8%aa%e9%9d%a2%e5%90%91%e5%af%b9%e8%b1%a1%e7%9a%84%e5%a5%bd%e4%b9%a0%e6%83%af.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>产品经理们，遇到Bug请别十万火急</title>
		<link>http://www.phpboke.com/pmbu.html</link>
		<comments>http://www.phpboke.com/pmbu.html#comments</comments>
		<pubDate>Mon, 27 Feb 2012 10:12:16 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[程序员]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=805</guid>
		<description><![CDATA[如果你希望成为一个失败的产品经理，在遇到bug时，请立即动手修复它。如果bug可以立即被修复，为何要一拖再拖？PM应该是一位“执行者”，而非总是 纸上谈兵的“思考者”。当问题出现后，必须在第一时间搞定它。当然，这样做可能浪费大量的时间，也可能分散精力，不过这是一位PM的最佳时间分配方式，不 是吗？
如果你希望成为一个成功的产品经理，在遇到bug时，请不要总是立即着急的修复它。不可否认，我们在遇到问题时，总是迫不及待的想改正。然而事实上，其实根本不用那么的十万火急，理由如下：
如果迅速解决了问题，你可能会忽略问题的根本原因。在大多数时候，每个问题都有其根本诱因。在问题刚暴露的时候，诱因一般深藏不露，有很多的可能性。笔者认为，根本诱因最可能来自于需求确认阶段。
同 样，在产品管理的其他阶段，这个理论也适用。有些问题可以很容易就找到根本诱因，但产品开发的真正挑战来自各种不稳定的因素。例如，有时候一款漏洞百出的 产品在上线之初，只暴露了冰山一角：一个很小的Bug，似乎十分容易解决。另一个例子，开发过程中，团队成员对各项功能的优先级有争议时，靠“民主投票” 来做决策，而忘了引发争议的源头：对产品远景、战略及计划缺乏共识。
医生治疗的是疾病，而不是治疗症状（译注：治疗感冒或支气管炎，而非咳嗽）。医生的任务不是治标，而是治本。对于PM而言，道理一模一样。
让问题暴露一段时间，或许是让大家认识到其严重性的唯一方法。很多父母都会说，他们的小孩吃一堑才长一 智——例如，不去摸滚烫的炭炉——若小孩自己被炭炉烫伤一次后，他们自然会明白那东西是摸不得的。在产品开发过程中，存在着同样的道理。当你试图请同事修 改或改进某功能时，你需要解释这是为了什么。如果大家不明白改进的意义，自然会无动于衷。
举个例子，假设你发现团队使用的需求管理软件存在着很大的问题，假如你希望马上修改它，或许得花大量精 力去告诉大家修改的意义，还得制作demo 进行 说明。但如果让这个需求管理软件继续运转一段时间，让它自己暴露出弱点，可能是一种更好的办法。因为需求管理软件的问题，在新产品上线前，你会发现有些最 初制定的需求并没有实现。此时，你可以告知大家这些遗漏的需求，但是不需要为之耽误了上线时间。如果你是正确的，要不了多久，大家就会意识到，因为使用了 那个糟糕的需求管理软件，才导致产品出现一些无法挽救的Bug。
提醒，本方法需十分小心的使用。作为PM，就算你本意是为了让同事们更透彻的看清问题，也不能忘了你是该产品最终成败的负责人。所以多数情况下，使用本方法时，最好选择小项目来作为案例。
问题可能没有你想象中那么严重。每次问题出现的时候——产品暴露了Bug，用户发出抱怨，会议上的争论——看上去总是迫切得非解决不可。于是，PM不得不暂时暂停正在进行的真正关键工作——战略、计划、用户调研——而把精力用在四处“灭火”上。
然而，必须立即解决的Bug其实很少。同时，与PM应该着重思考的产品方向等问题比起来，这些Bug的重要性实在很低。每个 Bug都有看上去万分关键的时刻，但过段时间后，它们似乎都变得无关紧要了。事实上，真正严重的Bug会迅速暴露出来。牢记这一点，会让PM把时间用在刀 刃上，而不是每天都在处理危机。
花更多的时间可以找到更完美的解决方案。若在全面了解Bug之前，就急着去为Bug寻找答案，我们通常会选择脑海中冒出来的第一 个解决方案。这可能也算是一个过得去的方案，不过若我们花更多时间来分析此Bug，找到其根本诱因，甚至来一场头脑风暴，或许我们能发现更完美的解决方 案。当然了，花更多时间也不一定就找得到更棒的方案，但至少，花了时间之后，得到的不会是更少的备选方案或更差的解决方案。
下一次遭遇Bug时，请别十万火急。PM需要有战略眼光（不是战术），请先分析Bug，找到根本诱因，并衡量全局重要性，再对 Bug进行解决。若不是每一次都着急解决每一个Bug，PM可以花更少的时间四处“灭火”，从而拥有更多的时间去思考产品战略——如何给用户带去更多的价 值。
]]></description>
			<content:encoded><![CDATA[<p>如果你希望成为一个失败的产品经理，在遇到bug时，请立即动手修复它。如果bug可以立即被修复，为何要一拖再拖？PM应该是一位“执行者”，而非总是 纸上谈兵的“思考者”。当问题出现后，必须在第一时间搞定它。当然，这样做可能浪费大量的时间，也可能分散精力，不过这是一位PM的最佳时间分配方式，不 是吗？</p>
<p>如果你希望成为一个成功的产品经理，在遇到bug时，请不要总是立即着急的修复它。不可否认，我们在遇到问题时，总是迫不及待的想改正。然而事实上，其实根本不用那么的十万火急，理由如下：<span id="more-805"></span></p>
<p>如果迅速解决了问题，你可能会忽略问题的根本原因。在大多数时候，每个问题都有其根本诱因。在问题刚暴露的时候，诱因一般深藏不露，有很多的可能性。笔者认为，根本诱因最可能来自于需求确认阶段。</p>
<p>同 样，在产品管理的其他阶段，这个理论也适用。有些问题可以很容易就找到根本诱因，但产品开发的真正挑战来自各种不稳定的因素。例如，有时候一款漏洞百出的 产品在上线之初，只暴露了冰山一角：一个很小的Bug，似乎十分容易解决。另一个例子，开发过程中，团队成员对各项功能的优先级有争议时，靠“民主投票” 来做决策，而忘了引发争议的源头：对产品远景、战略及计划缺乏共识。</p>
<p>医生治疗的是疾病，而不是治疗症状（译注：治疗感冒或支气管炎，而非咳嗽）。医生的任务不是治标，而是治本。对于PM而言，道理一模一样。</p>
<p>让问题暴露一段时间，或许是让大家认识到其严重性的唯一方法。很多父母都会说，他们的小孩吃一堑才长一 智——例如，不去摸滚烫的炭炉——若小孩自己被炭炉烫伤一次后，他们自然会明白那东西是摸不得的。在产品开发过程中，存在着同样的道理。当你试图请同事修 改或改进某功能时，你需要解释这是为了什么。如果大家不明白改进的意义，自然会无动于衷。</p>
<p>举个例子，假设你发现团队使用的需求管理软件存在着很大的问题，假如你希望马上修改它，或许得花大量精 力去告诉大家修改的意义，还得制作demo 进行 说明。但如果让这个需求管理软件继续运转一段时间，让它自己暴露出弱点，可能是一种更好的办法。因为需求管理软件的问题，在新产品上线前，你会发现有些最 初制定的需求并没有实现。此时，你可以告知大家这些遗漏的需求，但是不需要为之耽误了上线时间。如果你是正确的，要不了多久，大家就会意识到，因为使用了 那个糟糕的需求管理软件，才导致产品出现一些无法挽救的Bug。</p>
<p>提醒，本方法需十分小心的使用。作为PM，就算你本意是为了让同事们更透彻的看清问题，也不能忘了你是该产品最终成败的负责人。所以多数情况下，使用本方法时，最好选择小项目来作为案例。</p>
<p>问题可能没有你想象中那么严重。每次问题出现的时候——产品暴露了Bug，用户发出抱怨，会议上的争论——看上去总是迫切得非解决不可。于是，PM不得不暂时暂停正在进行的真正关键工作——战略、计划、用户调研——而把精力用在四处“灭火”上。</p>
<p>然而，必须立即解决的Bug其实很少。同时，与PM应该着重思考的产品方向等问题比起来，这些Bug的重要性实在很低。每个 Bug都有看上去万分关键的时刻，但过段时间后，它们似乎都变得无关紧要了。事实上，真正严重的Bug会迅速暴露出来。牢记这一点，会让PM把时间用在刀 刃上，而不是每天都在处理危机。</p>
<p>花更多的时间可以找到更完美的解决方案。若在全面了解Bug之前，就急着去为Bug寻找答案，我们通常会选择脑海中冒出来的第一 个解决方案。这可能也算是一个过得去的方案，不过若我们花更多时间来分析此Bug，找到其根本诱因，甚至来一场头脑风暴，或许我们能发现更完美的解决方 案。当然了，花更多时间也不一定就找得到更棒的方案，但至少，花了时间之后，得到的不会是更少的备选方案或更差的解决方案。</p>
<p>下一次遭遇Bug时，请别十万火急。PM需要有战略眼光（不是战术），请先分析Bug，找到根本诱因，并衡量全局重要性，再对 Bug进行解决。若不是每一次都着急解决每一个Bug，PM可以花更少的时间四处“灭火”，从而拥有更多的时间去思考产品战略——如何给用户带去更多的价 值。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/pmbu.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>写给刚刚上岗的网站技术人员</title>
		<link>http://www.phpboke.com/%e5%86%99%e7%bb%99%e5%88%9a%e5%88%9a%e4%b8%8a%e5%b2%97%e7%9a%84%e7%bd%91%e7%ab%99%e6%8a%80%e6%9c%af%e4%ba%ba%e5%91%98.html</link>
		<comments>http://www.phpboke.com/%e5%86%99%e7%bb%99%e5%88%9a%e5%88%9a%e4%b8%8a%e5%b2%97%e7%9a%84%e7%bd%91%e7%ab%99%e6%8a%80%e6%9c%af%e4%ba%ba%e5%91%98.html#comments</comments>
		<pubDate>Mon, 27 Feb 2012 10:09:33 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[程序员]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=802</guid>
		<description><![CDATA[工作5年了，网站相关的开发工作也干了4年多。负责带领团队也好几年了。面试和带领刚工作的人也不少了。其中的优秀者不少，但是大多数都存在下面提到的几个认识误区。把这些问题提出来，希望对刚参加工作没有多久的程序员们有所帮助，少走弯路。
公司招你进来，其实最重要的就是看到你的工作能力和工作态度是可以接受的。
工作能力指你能满足他们的工作期望，或者在可接受的时间范围内，经过培训后，可以满足这个工作期望。
工作态度指你能有些做职员的基本素质。
这个道理应该所有人都清楚。但是到实际事情时候就经常犯迷糊。下面几点是经常会出问题的地方：
1、不经测试，Review，就认为自己工作完成了。
你的代码或者应用一旦被别人Review ，或者进行试用。这时候你代码的好坏，或者功能是否在各种场景下是否可用，都会影响你这个人在上级及同事眼里的可信任度。
代码书写的规范，性能的高质量，各种功能在各个场景都可用，则表示你这个人是完全可信的。下次上级给你分派任务的时候，就可以给你更多的自由度来发挥。长此以往，前途和钱途自然就随手可得。
反之，代码不规范，功能好些场景不可用。这只能让上级或同事觉得你不可信任。每次都需要处理你带来的这些问题，说恶心点就是你每次拉完大便都没擦屁股，每 次都得你的同事和上级帮你擦屁股。数次都这样后，上级或同事下次跟你沟通的时候就会觉得你这个人不可信任，一件事情必须反复多次强调，总觉得你还会作出问 题。你的信用已经非常危险了。
你在别人眼里的信用就这样被你慢慢透支了。透支到一定程度，走人吧。整个团队的效率会因为你而变慢（每个人跟你沟通的成本都会影响到他本人的产出），你不走人谁走人。
2、最短可接受的工作时限
你有没有统计过，公司分派给你一个工作时候，上级指定的这项工作计划做多久的预计，跟你自己的预计有多大差异？
如果你预计时间大于上级给的工作计划时间，同时上级没有增派人手进行相关工作。除了BT的领导外，那只有一种情况：上级对你的工作态度非常不满，认为你的薪水对应的工作能力不是这么点。
对于刚工作的，更多的是你表现出来的工作能力在公司的平均工作能力之下。同时公司觉得你对工作没有表现出足够的热情。 一个能力在平均水平下面，又缺乏工作激情的人，他的前途在那里？？
如果这个人还没有表现出几个月后能达到平均水平之上的希望，为啥会留这样一个人呢？
3、工作能力不等于技术水平
我曾看到过有人抱怨说大公司的员工也不过是这技术水平， 这么简单的技术问题都不会。我自己早期也有这样想法，后来发现是不对的。
不论大公司还是小公司，要得是解决问题的工作能力。 我的曾经手下就有好几个技术水平很牛的，但是作出来的应用却一次次返工的。为啥，工作能力这些非技术因素他们做的很不好。
工作能力的非技术因素包括的很多： 责任心，表现就是对自己写出来的代码有一定要让人放心的责任； 沟通能力，一个典型的表现就是需求不理解或者需求不明时，及时得跟相关人沟通，而不是自己先按自己想法实现，造成代码写完后再返工的恶果等等。
技术水平低，但是解决问题能力强的，我也碰到过一些人。 工作的能力更重要的是这些非技术的工作能力，而不是技术水平。技术人员很容易技术水平高，但是非技术的工作能力差。 这是很糟糕的。
4、发展潜力，学习能力
公司使用的技术不可能一直不变，一直不变的公司只能慢慢被市场淘汰。这就要求员工能不断的学习新的知识，并应用到工作中来。
要想不会出现几年后，自己发现跳槽找个工作都没人要，赶快学习吧。
坚持，是一个人最难做到的。 但是不坚持，那就等着灭亡吧。
5、笨鸟先飞
一个人，在公司，如果工作能力在平均线以下， 加班吧， 不要有任何幻想。
最可怕的是自己没这个意识， 自认为自己技术水平很牛， 但是解决问题的工作能力却在平均水平线以下， 眼高手低 ， 这样的人， 公司是不能留的。
6、承诺到的事情一定要做到，不要找理由
一件事情没有被做完，想找理由能找很多的。既然你承诺了某个时间点前完成，就不要再找各种理由推脱。
公司同事和上级虽然可能这次接受了你的理由，但是下次呢， 慢慢的就会让你的上级，同事觉得你是一个喜欢推托的人。 感觉你干事是非常不可靠的。不知道那次就会不完成，下次谁敢再找你干事？
可能很多人在看到我这篇博客的时候，觉得我写的很刻薄，好像都是从公司的角度欺压技术人员。很没有人情味。
只要你不是公司的董事， 你永远是被剥削者，公司的目的就是利润最大化，这是公司存活的根本目的。作为普通的职员，要有所为的白领意识，其实就是被剥削意识。这是个适者生存的生态圈，不适用的人只能被淘汰。
实际的公司其实有很多人情味在里面，或者同事和领导有些话不便于说出口。 这也就造成了一些技术人员被开除，还自以为如何如何？ 都是没有这些意识造成的。我写这篇博客就是希望能增加技术人员的这些意识，不要犯了这些问题还自己不知道。
]]></description>
			<content:encoded><![CDATA[<p>工作5年了，网站相关的开发工作也干了4年多。负责带领团队也好几年了。面试和带领刚工作的人也不少了。其中的优秀者不少，但是大多数都存在下面提到的几个认识误区。把这些问题提出来，希望对刚参加工作没有多久的程序员们有所帮助，少走弯路。</p>
<p>公司招你进来，其实最重要的就是看到你的工作能力和工作态度是可以接受的。</p>
<p>工作能力指你能满足他们的工作期望，或者在可接受的时间范围内，经过培训后，可以满足这个工作期望。</p>
<p>工作态度指你能有些做职员的基本素质。</p>
<p>这个道理应该所有人都清楚。但是到实际事情时候就经常犯迷糊。下面几点是经常会出问题的地方：<span id="more-802"></span></p>
<p>1、不经测试，Review，就认为自己工作完成了。</p>
<p>你的代码或者应用一旦被别人Review ，或者进行试用。这时候你代码的好坏，或者功能是否在各种场景下是否可用，都会影响你这个人在上级及同事眼里的可信任度。</p>
<p>代码书写的规范，性能的高质量，各种功能在各个场景都可用，则表示你这个人是完全可信的。下次上级给你分派任务的时候，就可以给你更多的自由度来发挥。长此以往，前途和钱途自然就随手可得。</p>
<p>反之，代码不规范，功能好些场景不可用。这只能让上级或同事觉得你不可信任。每次都需要处理你带来的这些问题，说恶心点就是你每次拉完大便都没擦屁股，每 次都得你的同事和上级帮你擦屁股。数次都这样后，上级或同事下次跟你沟通的时候就会觉得你这个人不可信任，一件事情必须反复多次强调，总觉得你还会作出问 题。你的信用已经非常危险了。</p>
<p>你在别人眼里的信用就这样被你慢慢透支了。透支到一定程度，走人吧。整个团队的效率会因为你而变慢（每个人跟你沟通的成本都会影响到他本人的产出），你不走人谁走人。</p>
<p>2、最短可接受的工作时限</p>
<p>你有没有统计过，公司分派给你一个工作时候，上级指定的这项工作计划做多久的预计，跟你自己的预计有多大差异？</p>
<p>如果你预计时间大于上级给的工作计划时间，同时上级没有增派人手进行相关工作。除了BT的领导外，那只有一种情况：上级对你的工作态度非常不满，认为你的薪水对应的工作能力不是这么点。</p>
<p>对于刚工作的，更多的是你表现出来的工作能力在公司的平均工作能力之下。同时公司觉得你对工作没有表现出足够的热情。 一个能力在平均水平下面，又缺乏工作激情的人，他的前途在那里？？</p>
<p>如果这个人还没有表现出几个月后能达到平均水平之上的希望，为啥会留这样一个人呢？</p>
<p>3、工作能力不等于技术水平</p>
<p>我曾看到过有人抱怨说大公司的员工也不过是这技术水平， 这么简单的技术问题都不会。我自己早期也有这样想法，后来发现是不对的。</p>
<p>不论大公司还是小公司，要得是解决问题的工作能力。 我的曾经手下就有好几个技术水平很牛的，但是作出来的应用却一次次返工的。为啥，工作能力这些非技术因素他们做的很不好。</p>
<p>工作能力的非技术因素包括的很多： 责任心，表现就是对自己写出来的代码有一定要让人放心的责任； 沟通能力，一个典型的表现就是需求不理解或者需求不明时，及时得跟相关人沟通，而不是自己先按自己想法实现，造成代码写完后再返工的恶果等等。</p>
<p>技术水平低，但是解决问题能力强的，我也碰到过一些人。 工作的能力更重要的是这些非技术的工作能力，而不是技术水平。技术人员很容易技术水平高，但是非技术的工作能力差。 这是很糟糕的。</p>
<p>4、发展潜力，学习能力</p>
<p>公司使用的技术不可能一直不变，一直不变的公司只能慢慢被市场淘汰。这就要求员工能不断的学习新的知识，并应用到工作中来。</p>
<p>要想不会出现几年后，自己发现跳槽找个工作都没人要，赶快学习吧。</p>
<p>坚持，是一个人最难做到的。 但是不坚持，那就等着灭亡吧。</p>
<p>5、笨鸟先飞</p>
<p>一个人，在公司，如果工作能力在平均线以下， 加班吧， 不要有任何幻想。</p>
<p>最可怕的是自己没这个意识， 自认为自己技术水平很牛， 但是解决问题的工作能力却在平均水平线以下， 眼高手低 ， 这样的人， 公司是不能留的。</p>
<p>6、承诺到的事情一定要做到，不要找理由</p>
<p>一件事情没有被做完，想找理由能找很多的。既然你承诺了某个时间点前完成，就不要再找各种理由推脱。</p>
<p>公司同事和上级虽然可能这次接受了你的理由，但是下次呢， 慢慢的就会让你的上级，同事觉得你是一个喜欢推托的人。 感觉你干事是非常不可靠的。不知道那次就会不完成，下次谁敢再找你干事？</p>
<p>可能很多人在看到我这篇博客的时候，觉得我写的很刻薄，好像都是从公司的角度欺压技术人员。很没有人情味。</p>
<p>只要你不是公司的董事， 你永远是被剥削者，公司的目的就是利润最大化，这是公司存活的根本目的。作为普通的职员，要有所为的白领意识，其实就是被剥削意识。这是个适者生存的生态圈，不适用的人只能被淘汰。</p>
<p>实际的公司其实有很多人情味在里面，或者同事和领导有些话不便于说出口。 这也就造成了一些技术人员被开除，还自以为如何如何？ 都是没有这些意识造成的。我写这篇博客就是希望能增加技术人员的这些意识，不要犯了这些问题还自己不知道。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/%e5%86%99%e7%bb%99%e5%88%9a%e5%88%9a%e4%b8%8a%e5%b2%97%e7%9a%84%e7%bd%91%e7%ab%99%e6%8a%80%e6%9c%af%e4%ba%ba%e5%91%98.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web工程师的web架构设计经验分享</title>
		<link>http://www.phpboke.com/webdesign.html</link>
		<comments>http://www.phpboke.com/webdesign.html#comments</comments>
		<pubDate>Mon, 27 Feb 2012 10:00:51 +0000</pubDate>
		<dc:creator>ken</dc:creator>
				<category><![CDATA[程序员]]></category>
		<category><![CDATA[web架构]]></category>

		<guid isPermaLink="false">http://www.phpboke.com/?p=799</guid>
		<description><![CDATA[本人作为一位web工程师，着眼最多之处莫过于性能与架构，本次幸得参与sd2.0大会，得以与同行广泛交流,于此二方面，有些架构设计的心得，不敢独享，与众友分享，本文是这次参会与众同撩交流的心得.
架构设计的几个心得：

一，不要过设计：never over design

这是一个常常被提及的话题，但是只要想想你的架构里有多少功能是根本没有用到，或者最后废弃的，就能明白其重要性了，初涉架构设计，往往倾向于设计大而化 一的架构，希望设计出具有无比扩展性，能适应一切需求的增加架构，web开发领域是个非常动态的过程，我们很难预测下个星期的变化，而又需要对变化做出最 快最有效的响应。。
ebay的工程师说过，他们的架构设计从来都不能满足系统的增长，所以他们的系统永远都在推翻重做。请注意，不是ebay架构师的能力有问题，他们 设计的架构总是建立旧版本的瓶颈上，希望通过新的架构带来突破，然而新架构带来的突破总是在很短的时间内就被新增需求淹没，于是他们不得不又使用新的架构
web开发，是个非常敏捷的过程，变化随时都在产生，用户需求千变万化，许多方面偶然性非常高，较之软件开发，希望用一个架构规划以后的所有设计，是不现实的
二，web架构生命周期：web architecture‘s life cycle
既然要杜绝过设计，又要保证一定的前瞻性，那么怎么才能找到其中的平衡呢？希望下面的web架构生命周期能够帮到你

所设计的架构需要在1－10倍的增长下，通过简单的增加硬件容量就能够胜任，而在5－10倍的增长期间，请着手下一个版本的架构设计，使之能承受下一个10倍间的增长
google之所以能够称霸，不完全是因为搜索技术和排序技术有多先进，其实包括baidu和yahoo，所使用的技术现在也已经大同小异，然而，google能在一个月内通过增加上万台服务器来达到足够系统容量的能力确是很难被复制的

三，缓存：Cache
空间换取时间，缓存永远计算机设计的重中之重，从cpu到io，到处都可以看到缓存的身影，web架构设计重，缓存设计必不可少，关于怎样设计合理的缓 存，jbosscache的创始人，淘宝的创始人是这样说的：其实设计web缓存和企业级缓存是非常不同的，企业级缓存偏重于逻辑，而web缓存，简单快 速为好。。
缓存带来的问题是什么？是程序的复杂度上升，因为数据散布在多个进程，所以同步就是一个麻烦的问题，加上集群，复杂度会进一步提高，在实际运用中，采用怎样的同步策略常常需要和业务绑定
老钱为搜狐设计的帖子设计了链表缓存，这样既可以满足灵活插入的需要，又能够快速阅读，而其他一些大型社区也经常采用类此的结构来优化帖子列表，memcache也是一个常常用到的工具
Cache的常用的策略是：让数据在内存中，而不是在比较耗时的磁盘上。从这个角度讲，mysql提供的heap引擎（存储方式）也是一个值得思考的方法,这种存储方法可以把数据存储在内存中,并且保留sql强大的查询能力,是不是一举两得呢?
我们这里只说到了读缓存，其实还有一种写缓存，在以内容为主的社区里比较少用到，因为这样的社区最主要需要解决的问题是读问题，但是在处理能力低于 请求能力时，或者单个希望请求先被缓存形成块，然后批量处理时，写缓存就出现了，在交互性很强的社区设计里我们很容易找到这样的缓存
四，核心模块一定要自己开发：DIY your core module
这点我们是深有体会，钱宏武和云风也都有谈到，我们经常倾向于使用一些开源模块，如果不涉及核心模块，确实是可以的，如果涉及，那么就要小心了，因为当访 问量达到一定的程度，这些模块往往都有这样那样的问题，当然我们可以把问题归结为对开源的模块不熟悉，但是不管怎样，核心出现问题的时候，不能完全掌握其 代码是非常可怕的

五，合理选择数据存储方式：reasonable data storage
我们一定要使用数据库吗，不一定，雷鸣告诉我们搜索不一定需要数据库，云风告诉我们，游戏不一定需要数据库，那么什么时候我们才需要数据库呢，为什么不干脆用文件来代替他呢？
首先我们需要先承认，数据库也是对文件进行操作。我们需要数据库，主要是使用下面这几个功能，一个是数据存储，一个是数据检索，在关系数据库中，我们其实非常在乎数据库的复杂搜索的能力，看看一个统计用的tsql就知道了(不用仔细读,扫一眼就可以了)
select   c.Class_name,d.Class_name_2,a.Creativity_Title,b.User_name,(select   count(Id)   from   review   where   Reviewid=a.Id)   as   countNum   from   Creativity   as   a,User_info   as   b,class   as   c,class2   as   d   where   a.user_id=b.id   and   a.Creativity_Class=c.Id   and   a.Creativity_Class_2=d.Id
select   a.Id,max(c.Class_name),(max(d.Class_name_2),max(a.Creativity_Title),max(b.User_name),count(e.Id)   as   countNum   from   Creativity   as   a,User_info   as   b,class   as   c,class2   as   [...]]]></description>
			<content:encoded><![CDATA[<p>本人作为一位web工程师，着眼最多之处莫过于性能与架构，本次幸得参与sd2.0大会，得以与同行广泛交流,于此二方面，有些架构设计的心得，不敢独享，与众友分享，本文是这次参会与众同撩交流的心得.</p>
<p>架构设计的几个心得：</p>
<p><strong><br />
一，不要过设计：never over design<br />
</strong><br />
这是一个常常被提及的话题，但是只要想想你的架构里有多少功能是根本没有用到，或者最后废弃的，就能明白其重要性了，初涉架构设计，往往倾向于设计大而化 一的架构，希望设计出具有无比扩展性，能适应一切需求的增加架构，web开发领域是个非常动态的过程，我们很难预测下个星期的变化，而又需要对变化做出最 快最有效的响应。。<span id="more-799"></span></p>
<p>ebay的工程师说过，他们的架构设计从来都不能满足系统的增长，所以他们的系统永远都在推翻重做。请注意，不是ebay架构师的能力有问题，他们 设计的架构总是建立旧版本的瓶颈上，希望通过新的架构带来突破，然而新架构带来的突破总是在很短的时间内就被新增需求淹没，于是他们不得不又使用新的架构<br />
web开发，是个非常敏捷的过程，变化随时都在产生，用户需求千变万化，许多方面偶然性非常高，较之软件开发，希望用一个架构规划以后的所有设计，是不现实的</p>
<p><strong>二，web架构生命周期：web architecture‘s life cycle</strong><br />
既然要杜绝过设计，又要保证一定的前瞻性，那么怎么才能找到其中的平衡呢？希望下面的web架构生命周期能够帮到你</p>
<p><img src="http://www.phpv.net/uploadfile/month_200901/local_lXs4U2euHs.gif" border="0" alt="architecture_life_cycle" /></p>
<p>所设计的架构需要在1－10倍的增长下，通过简单的增加硬件容量就能够胜任，而在5－10倍的增长期间，请着手下一个版本的架构设计，使之能承受下一个10倍间的增长</p>
<p>google之所以能够称霸，不完全是因为搜索技术和排序技术有多先进，其实包括baidu和yahoo，所使用的技术现在也已经大同小异，然而，google能在一个月内通过增加上万台服务器来达到足够系统容量的能力确是很难被复制的</p>
<p><strong><br />
三，缓存：Cache</strong><br />
空间换取时间，缓存永远计算机设计的重中之重，从cpu到io，到处都可以看到缓存的身影，web架构设计重，缓存设计必不可少，关于怎样设计合理的缓 存，jbosscache的创始人，淘宝的创始人是这样说的：其实设计web缓存和企业级缓存是非常不同的，企业级缓存偏重于逻辑，而web缓存，简单快 速为好。。</p>
<p>缓存带来的问题是什么？是程序的复杂度上升，因为数据散布在多个进程，所以同步就是一个麻烦的问题，加上集群，复杂度会进一步提高，在实际运用中，采用怎样的同步策略常常需要和业务绑定</p>
<p>老钱为搜狐设计的帖子设计了链表缓存，这样既可以满足灵活插入的需要，又能够快速阅读，而其他一些大型社区也经常采用类此的结构来优化帖子列表，memcache也是一个常常用到的工具</p>
<p>Cache的常用的策略是：让数据在内存中，而不是在比较耗时的磁盘上。从这个角度讲，mysql提供的heap引擎（存储方式）也是一个值得思考的方法,这种存储方法可以把数据存储在内存中,并且保留sql强大的查询能力,是不是一举两得呢?</p>
<p>我们这里只说到了读缓存，其实还有一种写缓存，在以内容为主的社区里比较少用到，因为这样的社区最主要需要解决的问题是读问题，但是在处理能力低于 请求能力时，或者单个希望请求先被缓存形成块，然后批量处理时，写缓存就出现了，在交互性很强的社区设计里我们很容易找到这样的缓存</p>
<p><strong>四，核心模块一定要自己开发：DIY your core module</strong><br />
这点我们是深有体会，钱宏武和云风也都有谈到，我们经常倾向于使用一些开源模块，如果不涉及核心模块，确实是可以的，如果涉及，那么就要小心了，因为当访 问量达到一定的程度，这些模块往往都有这样那样的问题，当然我们可以把问题归结为对开源的模块不熟悉，但是不管怎样，核心出现问题的时候，不能完全掌握其 代码是非常可怕的</p>
<p><strong><br />
五，合理选择数据存储方式：reasonable data storage</strong><br />
我们一定要使用数据库吗，不一定，雷鸣告诉我们搜索不一定需要数据库，云风告诉我们，游戏不一定需要数据库，那么什么时候我们才需要数据库呢，为什么不干脆用文件来代替他呢？<br />
首先我们需要先承认，数据库也是对文件进行操作。我们需要数据库，主要是使用下面这几个功能，一个是数据存储，一个是数据检索，在关系数据库中，我们其实非常在乎数据库的复杂搜索的能力，看看一个统计用的tsql就知道了(不用仔细读,扫一眼就可以了)</p>
<p>select   c.Class_name,d.Class_name_2,a.Creativity_Title,b.User_name,(select   count(Id)   from   review   where   Reviewid=a.Id)   as   countNum   from   Creativity   as   a,User_info   as   b,class   as   c,class2   as   d   where   a.user_id=b.id   and   a.Creativity_Class=c.Id   and   a.Creativity_Class_2=d.Id<br />
select   a.Id,max(c.Class_name),(max(d.Class_name_2),max(a.Creativity_Title),max(b.User_name),count(e.Id)   as   countNum   from   Creativity   as   a,User_info   as   b,class   as   c,class2   as   d,review   as   e   where   a.user_id=b.id   and   a.Creativity_Class=c.Id   and   a.Creativity_Class_2=d.Id   and   a.Id=e.Reviewid   group   by   a.Id &#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;&#8230;.</p>
<p>我们可以看出需要数据库关联，排序的能力，这个能力在某些情况下非常重要，但是如果你的网站的常规操作，全是这样复杂的逻辑，那效率一定是非常低 的，所以我们常常在数据库里加入许多冗余字段，来减小简单查询时关联等操作带来的压力，我们看看下面这张图，可以看到数据库的设计重心，和网站(指内容型 社区)需要面对的问题实际是有一些偏差的</p>
<p><img src="http://www.phpv.net/uploadfile/month_200901/local_KZwqkiaJ1Y.gif" alt="database" width="664" height="495" /></p>
<p>同样其他一些软件产品也遇到同样的问题所以具我了解，有许多特殊的运用都有自己设计的特殊数据存储结构与方法，比如有的大型服务程序采取树形数据存储结构，lucene使用文件来存储索引和文件</p>
<p>从另外一个角度上看，使用数据库，意味着数据和表现是完全分离的（这当然是经典的设计思路），也就是说当需要展示数据时，不得不需要一个转换的过 程，也可以说是绑定的过程，当网站具备一定规模的时候，数据库往往成为效率的瓶颈，所以许多网站也采用直接书写静态文件的方法来避免读取操作时的绑定</p>
<p>这并不是说我们从今天起就可以把我们亲爱的数据库打入冷宫，而是我们在设计数据的持久化时，需要根据实际情况来选择存储方式，而数据库不过是其中一个选项</p>
<p><strong><br />
六，搞清楚谁是最重要的人：who&#8217;s the most important guy</strong><br />
在用例需求分析的时候常常讲到涉众，就是和你的设计息息相关的人，在web中我们一定以为最重要的涉众莫过于用户了。，在一个传统的互动社 区开发中，最重要的东西是内容，用户产生内容，所以用户就是上帝，至于内容挑选工具，不就是给坐我后面三排的妹妹们用的吗？凑或行了，实在有问题我就在数 据里手动帮你加得了。。这大概是眼下许多小型甚至中型网站技术人员的普遍想法。钱宏武在他的讲座里谈到了这个问题：实际上网站每天产生的内容非常的多，普 通人是不可能看完的，而编辑负责把精华的内容推荐到首页上，所以很多用户读到的内容其实都依赖于编辑的推荐，所以设计让编辑工作方便的工具也是非常重要， 有时甚至是最重要的。</p>
<p><strong><br />
七，不要执着于文档：don&#8217;t be crazy about document</strong><br />
web开发的文档重要吗？什么文档最重要？我的看法是web开发中交流<strong>&gt;</strong>文档，</p>
<p>现在大的软件公司比较流行的做法是：<br />
注重产品设计文档，在这种方法里，产品文档非常详尽，并且没有歧义，开发人员基于设计文档开发，测试人员基于设计文档制定测试方案，任何新人都可以通过阅读产品设计文档来了解项目的概况</p>
<p>而web项目从概念到实现的时间是非常短的，而且越短越好，并且由于变化迅速，要想写出完整的产品和需求文档是几乎不可能的，大多数情况是等你写出 完备的文档，项目早就是另外一个样子，但是没有文档的问题是，如果团队发生变化，添加新成员怎样才能了解软件的结构和概念呢，一种是每个人都了解软件的整 个结构，除非你的团队整体消失，否则任何一个人都能够担当培养新人的责任，这种face2face交流比文档有效率很多。</p>
<p>于是就有了前office开发者，现任yahoo中国某产品开发负责人的刘振飞所感觉到的落差，他说，<strong>我们的项目是吵出来的</strong>，我听完会心一笑</p>
<p><strong><br />
八，团队：team</strong><br />
不要专家团队，而要外科手术式的团队,你的团队里一定要有清道夫，需要有弓箭手，让他们和项目一起成长，才是项目负责人的最大成就</p>
<p><strong>总结：</strong></p>
<p>架构是一种权衡</p>
<p><img src="http://www.phpv.net/uploadfile/month_200901/local_DvK03lBCvX.gif" alt="architecture" /></p>
<p>web开发的特点是是：没有太复杂的技术难点，一切在于迅速的把握需求，其实这正式敏捷开发的要旨所在，一切都可以非常快速的建立，非常快速的重构，我们的开发工具，底层库和框架，包括搜索引擎和web文档提供的帮助，都提我们供给了敏捷的能力。</p>
<p>此外，相应的，最有效率的交流方式必须留给web开发，那就是face2face（面对面），不要太担心你的设计不能被完备的文档所保留下来，他们会以交流，代码和小卡片的方式保存下来</p>
<p>人的因素会更加重要，无论是对用户的需求，还是开发人员的素质。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.phpboke.com/webdesign.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

