存档

文章标签 ‘PHP’

听小韩聊PHP项目开发(3)–切分你的系统

2010年7月12日
本文章为 听小韩聊PHP项目开发 系列中的第3 篇(共3篇)

【写在前面的话:看看本文的时间,最后一次保存是去年的八月份,想想,还是先发表一下,然后待续,老规矩,在本文完成之前请不要转载。】

你是一个有控制欲的人么?你希望把控你的项目么?那么,切分他们吧。

1、为什么要切分你的项目

我们是邪恶的 -.-。我们希望把控我们的项目,所以,我们需要切分它。

想像一下,你有一个生日蛋糕,你想吃掉它,那么,按照惯例,作为寿星的你,应该先切分它,什么?你还要点蜡烛?OMG,你要在吹蜡烛时喷口水在蛋糕上吗?你的口味好重。

切分代码,大体上来说,在控制进度、应对变化、简化逻辑、代码复用、分工协作等方面,都有相当的好处。

1.1、控制进度

首先来说控制进度,当你开始开发一个大型站点时(当然,更多的时候是“你们”),作为项目经理的你来讲,你需要时不时的应对来自你的上级或者你的客户的询问–“小韩,做了多少了,还有多久能做完啊”。这个时候,你总不能说,“哦,我做了一些了,还有一段时间能做完。”

你的领导希望听到的是,系统一共有x个模块,我做完了x个,剩下x个模块,难度有些大,可能还需要x天的时间,等所有模块都完成了,再整体整合测试一下,就OK了。这样回答,我想你的表现会让你的领导觉得,你是一个思路清晰,能够把控的项目管理人员。这里再容我跑题一下,一般认为,管理职能分为“计划、组织、协调、控制”等。其中“计划”则首先依赖于对项目的切分,如果不能切分项目,则无从进行计划。

1.2、应对变化

我们都知道,项目,尤其是软件项目是多变的,这种变化可能来自于前期沟通的不完善,也可能来自于随着时间的发展,客户或软件使用者的需求随之发展而发生变化。如果项目中所有的部分都是互相缠绕的,那么则牵一发而动全身,你甚至无法对一个简单的变量名进行改变,而使得系统的其他部分不受到干扰。然而此时,如果对系统进行划分,将其分为若干层次、若干模块,层次与层次、模块与模块之间通过既定协议(如接口)进行通讯,则可以将原有的整体复杂系统切分为若干个子系统、子模块、子程序,各程序只要保持其输入、输出不变,则其内部的代码可以方便的更改而不怕会影响到外部。

我举个例子来讲,你可能用以下代码处理用户的登录以及其登录会话的持久化(Session)。

//登录代码
if($success_login) //假设$success_login为上一步判断用户名密码正确与否的标记
{
  $_SESSION['user_name'] = $user_name;
  $_SESSION['password'] = $password;
}

而使用如下代码判断是否登录

if(isset($_SESSION['user_name']))
{
  //do something
}

那么假设有一天,你想使用username作为保存用户名的Session变量名称,则你需要找出所有形如$_SESSION['user_name']的代码,并修改,一旦有遗漏,你的程序将会出现难以查找的bug。

这就是因为在代码中,把用户登录会话的部分耦合在了全部的系统当中。实际上,你应该专门有一个管理用户登录会话的模块,比如叫做SessionManager,你的代码则可能变为这样:

/**
* 设定登录会话
*/
if($success_login) //假设$success_login为上一步判断用户名密码正确与否的标记
{
 SessionManager::SetLoginUser($user);
}
 
/**
* 判断登录状态
*/
if(SessionManager::IsLogined())
{
 //do something
}

这样,你在系统中,无需过度关注用户会话保存的具体实现,只要去调用SessionManager这个管理器的相关方法就可以了,而一旦发生前面提到的变化,你可以在SessionManager的内部完成此修改,而不会将这个问题渲染到全部代码。

1.3、简化逻辑

也许大部分普通的Web站点并没有复杂的逻辑,但是,随着网络世界越来越精彩,Web站点也会逐渐面临处理复杂逻辑的任务。一旦你面临复杂的系统,其中可能难倒你的,大部分不会是技术问题,而是逻辑问题,我们应当承认我们人类中的大部分,思维的稳定性和思维长度,都是有限的,我举个例子来说,在下棋的时候,在头脑中演算下一步应该如何走,对手针对你的下一步如何走这样的逻辑,没有经过一定锻炼的人,是不可能演算很多步的。对于系统逻辑来说也是一样的,同时考虑过多的问题,以及这些问题之间的关系,会让你无法承受,然而此时将一个大的、复杂的问题切分为若干小问题,在同一时刻只关注一个小问题,则可以让自己轻松快乐的去进行程序的编写。再举个例子,比如我们要写一个MSN的客户端,那么实际上是有很多问题要考虑的,你的程序如何与服务器通讯,如何构造和发送数据,如何接受和处理数据,如何将数据显示在界面上……so many,这个时候你可以将你的系统切分为若干的模块,有的模块去处理网络通讯,有的去处理数据包的解析和构造,有的去处理界面显示,有的去处理各种事件的调度,等等等等,在各个模块中,你还可以进一步划分,直到单个类遵循单一职责原则,而一个模块间各个类都是聚合的……等等等等,这里有很多方法和技巧,我们稍后会详细讨论。

1.4、代码复用

代码复用的一个重要基础是分割变化与不变的部分,并分别进行编程。还以我们上面的MSN客户端的例子来说,其处理网络通讯的模块,在其他的程序中是不是也可以使用呢?答案是肯定的,但是……这要求你能够良好设计这个模块,权衡其边界,以使其具有普适性。这种基础类的实现,不应当关联具体项目的问题,比如说最简单的,你的方法名,不应当叫做send_msn_request,而只是send_request,这只是一个很简单的例子,但是却说明了,你要考虑你系统中的某些聚合功能,是不是可以在其他项目中使用的,如果是,请将其切分出来,并撰写并非是与当前项目紧密耦合的代码,你可以使用一个适配器将其配接到当前项目中,而不是将其直接为当前项目撰写。

关于代码复用的内容,您还可以查看http://www.ibm.com/developerworks/cn/java/reuse/获得更多信息。

1.5、分工协作

分工协作首先要求在“工”上有的可分,现代生产是要求详细分工,流水线方式作业的,试想,哪怕一个简单的MP3,有做芯片的机器,有开发嵌入式系统的工程师,还有利用模具生产的合作工厂,最后将各个部分拼接起来,成为你手中那个会发声、可以控制的小玩意。程序开发也是一样的。每一个系统,无论简单复杂,总是由若干个子系统组成的,这些子系统通常是功能内聚的,并通过某些特定方式与其他子系统进行协作。简单说,你所看到的这个WordPress的系统,有文章的子模块、有分类/Tag的子模块,那么我们是否可以让两个人分别去开发文章的子模块和分类/Tag的子模块呢,答案是肯定的,合作者首先坐在一起,定义各自的系统边界,开发分类/Tag子模块的工程师无需了解文章是由标题、内容,甚至图片组成的,他只了解,需要给特定的文章(通过文章的id来作为关键标记),进行分类,或者标记Tag,同理,开发文章子模块的工程师也无需了解Tag和分类的区别,只需要做他的文章模块的CURD就可以了,彼此之间不需要了解太多,是增强系统稳定性,在变化时可以敏捷修改而不担心影响其他部分的重要方式。这可以降低系统的开发和修改成本,工程师之间不必担心进行了重复的工作,因为子系统边界已经确定,每个人需要做什么是非常清晰的,同时,他们不必担心他们所完成的功能如何被调用,因为这些调用规则在切分系统时就明确了。他们也不必考虑其他子系统是否会影响他的系统,包括其他子系统的bug或者修改,因为各子系统是高内聚、低耦合的,子系统的具体实现方式不会过多影响其他系统。

2、如何切分你的系统

切分系统是一种艺术而不是一种技术。从不同的角度看某个物体,你会得到不同的投影,一个正方形的投影,那么其原物体一定是正方体吗,当然未必。从不同的角度看待系统,就会有不同的切分方式。而我们要做的就是,试图从各个角度来看待系统,避免盲人摸象,最终选择一种权衡的、折衷的,对于系统的发展方向最契合的方式来切分。不同的程序员有不同的切分习惯,而我们也无法武断的去说一定要按照某种方式切分。毕竟,我们不是为了切分系统而切分,而是要达成某种目的,这些目的我在上面笼统的谈过,比如说,针对分工协作,如果团队中程序员的水平有一定差距,那么可以将相对内核的复杂部分切出来,交由有经验的程序员来完成,即时它可能在其他方面并不能达到你的目的。

切分系统有几种角度,让我们由浅入深的聊一聊。

2.1、横向切分

对于系统的切分,横向切分是最常见的,例如MVC模式:MVC(Model-View-Controller,模型—视图—控制器模式)用于表示一种软件架构模式。它把软件系统分为三个基本部分:模型(Model),视图(View)和控制器(Controller)。

这种切分方式主要考虑了系统是由几个层次来完成的,各个层次之间的功能是内聚的,比如在MVC中,Model层负责数据交互,它永远不必理解数据在界面上是如何展示的,同理,View层也不必理解数据是从MySQL数据库还是SQL Server甚至是文件中的哪个取出的。

这种层次的划分,可以将系统功能划分为几个大部分,这几个大部分相对独立,然而又通过行为/数据被粘合在一起,从而使得其中某个部分发生变化时,其他部分不至于那么敏感,比如,网站的界面是会频繁改版的,然而你会发现,几乎大部分情况都是,界面上的元素摆放发生了变化,但是数据本身并没有任何变化,那么我们只需要改变View层就可以了,你的C和M层的代码一点都不用改动。

另一个名词叫做“三层架构”,实际上和MVC类似,也有人将MVC直接成为三层架构。其代表是微软的示例程序PetShop(架构详细分析看这里)。其将系统大致分为DAL(Data Access Level,数据访问层)、BLL(Bussines Logic Level,业务逻辑层)以及界面表示层。

但是,我窃以为,仅有MVC是不够的。在MVC中,Model层的功能实际上是可以再分为数据逻辑和业务逻辑两个层次,即更倾向于三层架构。业务逻辑层可以复用多个数据逻辑层,这在仅有Model层的系统中是难以做到的,同时,业务逻辑是可能发生频繁变更的,此时简单的数据逻辑并没有发生任何变化,不需要花代价和承担风险进行修改。我举个例子来说,我们要设计一个用户系统,该系统有注册、登录、修改信息等功能,此时,我们可以根据需求制定出一个业务逻辑层,你可以将其叫做LogicOperation/UserOperation层(下文简称UserOper),在该层中切合需求进行功能的设计,即Login、Regist、ModifyInfo,那么,我们是否在这个层次中就开始撰写关于数据库操作的代码呢,答案是否定的,因为你会发现,在Login功能中,你需要去查询用户名是否存在这样的信息,在Regist中,你同样会查询该信息,此时,你应该继续抽象出一个功能相对原子化的数据操作层,即DataManager/UserManager,在UserManager中,实现标准的CURD(Create、Update、Read、Delete)功能,以及某些可能用到的其他功能,但是这些方法应该是原子化的,可以由UserOper组合调用,例如在Regist中,可能通过UserManager的IsAccountExist方法查询用户名是否存在,然后用CreateUser方法建立用户,而在Login中,首先通过IsAccountExist方法查询用户名是否存在,然后用ReadUserByAccount方法来获得用户信息,并继而比对密码,等等,你会发现,LogicOperation层是对DataManager层方法的组合调用,而其组合方式就是具体的业务逻辑。

2.2、纵向切分

2.3、混合切分

2.4、切分粒度

3、切分案例

3.1、一个CMS系统的切分

3.2、一个博客系统的切分

3.3、一个校内网APP程序的切分

4、切分作业

Web服务器端技术 ,

听小韩聊PHP项目开发(2)–观察你的项目

2009年6月28日
本文章为 听小韩聊PHP项目开发 系列中的第2 篇(共3篇)

Hello,时隔半年,我终于继续了 =.=

1、为什么要观察你的项目–需求的重要性。

俗话说,磨刀不误砍柴工,当开始一个项目时,我希望你就像在街上看到了美女,你要先好好打量打量,然后再思考,“啊,我怎么去问她的电话呢~”

So,same as our projects.

当开始一个项目时,你应当首先审视的是项目的需求,要注意了,除非是你自己为自己闲着没事做的东西,其他的项目,都是为别人做的,怎么理解呢,我的意思是说,你项目的目的就是满足别人的需求。软件实际上是一种商品。所谓商品,就是商品是为交换而生产(或用于交换)的对他人或社会有用的劳动产品[百度百科]。请注意“对他人或社会有用”,这就是在讲,我们所编写的软件是为了满足需求而存在的,如果不能满足需求,哪怕你用了再高的技术,软件做的再漂亮,运行效率再高,都不能被称之为一款合格的软件。

为什么突然要扯这么远呢,是因为,我曾经和很多人一样,在做开发的时候,开始的时候无时不刻的都在想,这个东西有什么技术创新点,什么地方的效率会很低,应该解决,后来我听到了一句话,叫做“过早优化是万恶之源(premature optimization is the root of all evil–Donald Knuth)”,可能的确有那样一些项目,他们要求很高的效率,或者,该项目的需求者一直在询问你关于效率的问题,但是无论如何,在你什么都没有的时候,你就什么都不能做,就像你并没有一个女儿,你却时刻想着如何去打扮她一样毫无意义。

请记住,我们所编写的软件,它的第一要务是满足需求,当然,运行效率、界面美化可能是需求的一部分(非功能性需求,我们稍后会谈到),但是请将其作为需求考虑,而不是贯穿软件的全部。

关于需求,这里有一幅漫画,来源未知(提示:你可以点击图片放大):

另外还有此图片的中文版:http://picasaweb.google.com/lh/photo/ZK59I5p5-jfsc7kl213htQ?feat=directlink

2、我要观察到什么–什么是需求

“需求是产品必须完成的事以及必须具备的品质。需求存在的原因要么是该类型的产品要求一定的功能和品质,要么是客户希望需求成为交付的产品的一部分。”

–《掌握需求过程》ISBN:9787115159830

从上面的漫画中,可以很有趣的发现,由于沟通方式,对目标的理解差异和技术水平的不同,都会让需求在传递中发生变化,这种变化有时可能是致命的,我们人类在沟通时多采用语言,然而语言,尤其是口头语言,极易发生变化。因此,就需要大家对需求有一个统一的认识,什么是需求,需求应该包括哪些内容,不应该包括哪些内容,应该如何去分析需求。

本节引言中的话,严格来讲不是对需求的定义,让我们来看IEEE软件工程标准词汇表(1997年)中“需求”的定义:

(1)用户解决问题或达到目标所需的条件或权能(Capability)。

(2)系统或系统部件要满足合同、标准、规范或其它正式规定文档所需具有的条件或权能。

(3)一种反映上面(1)或(2)所描述的条件或权能的文档说明

软件需求包括三个不同的层次—业务需求、用户需求和功能需求—也包括非功能需求。业务需求( business requirement)反映了组织机构或客户对系统、产品高层次的目标要求,它们在项目视图与范围文档中予以说明。用户需求(user requirement) 文档描述了用户使用产品必须要完成的任务,这在使用实例(use case)文档或方案脚本(scenario)说明中予以说明。功能需求(functional requirement)定义了开发人员必须实现的软件功能,使得用户能完成他们的任务,从而满足了业务需求。所谓特性(feature)是指逻辑上相关 的功能需求的集合,给用户提供处理能力并满足业务需求。

简单来说,需求就是说明你软件将要满足的用户需要,需求是你软件的功能列表,这里的功能可能包括看得见的功能和看不见的功能。同时需要注意实际用户(用户是重要的需求分析参与者,难以想象一个只有开发者而没有用户参与的需求分析,所得出的是什么)可能对需求的理解有误,有时他们甚至不了解活无法向你描述出他的需求,也有时,他会“啰啰嗦嗦”的向你讲一堆不是需求的东西。

同时,需求还包括非功能的部分,例如,“单次搜索查询必须在0.1秒内完成”、“用户传输文件的速度不应低于其网络最高可用带宽的50%”,这些内容并非软件的功能性要求,但是实际上是软件的使用者使用软件体验、感受的重要感受点甚至是其是否能完成功能性需求的制约。

3、我没有马王爷的第三只眼–那么我如何分析需求呢

哦,这很麻烦,是的,好吧,我们退一步,作为开发人员,你可以让你的产品经理去和客户打交道,但是你必须和你的产品经理打交道,同时,你还必须和你的代码打交道。

与产品经理打交道和与代码打交道是两码事,八杆子打不到一块,你不能和产品经理讲if(xxx)  {} ,也不能去问你的代码,这里是让用户操作的,还是你丫自动操作的。

在与产品人员打交道时,你有责任用他们的语言来描述问题,这并不是单纯为了对方能够听懂你说什么,更重要的是,这会大大减少你们在交流沟通中的误解。所以,熟知你所在的行业,熟悉他们的业务,如果你要开发财务系统,请去阅读财会相关书籍,如果你要开发ERP系统,请去和工人师傅、基层管理人员多聊聊,在拓展你领域的同时,也会让你对你的编程思想有新的看法。

在与代码打交道的时候,你需要是一个好的建筑师,你应当构建严谨、运行健壮、可扩展性强的代码,这要求你在充分理解需求的情况下,看到需求的发展方向以及需求中可能发生变动的情况,甚至你需要和产品经理、客户去沟通,提出你的想法,当你问道“我觉得这里这样做的话,系统可能存在不稳定的因素,如果怎么怎么样做,不仅系统稳定了,您的操作也会更方便”,客户恍然大悟,你又减轻了工作量,何乐不为呢。

在理解需求、分析系统时,我建议你首先这样做:

将系统中存在的活动者都列出来,然后依次列出他们的操作功能和反应。

比如,一个简单的文章系统,我们可能这样去描述它

普通用户:注册、登录、找回密码、修改个人信息、查看类别、查看文章、查看某个类别下的文章、输入关键字搜索文章、发表评论、当别人发表对自己评论的回复时收到邮件。
管理员:查看用户信息、CURD(Create-Update-Read-Delete)类别、CURD文章

在上面的需求描述中,涉及了两个活动者,分别是“普通用户”和“管理员”,同时两个活动者都有若干功能,其中“普通用户”的“当别人发表对自己评论的回复时收到邮件”实际上不是用户的主动操作,而是用户对某个操作的反应,需要注意的是,这样的信息也需要在需求分析中体现。

需求分析可以体现为UML用例图,其好处是更直观,同时由于是统一化的表达,更有助于沟通,其他程序员可以更方便的理解你的意思,而不容易出现理解误差。

关于UML用例图方面的内容,可以到http://hi.baidu.com/jyangstu/blog/item/5d2f89131ef270c6c3fd7833.html查看一份简介。

我的需求方法实际上是用例图的一个超级简版,这个方法不能体现活动者与活动者、用例与用例(就是活动者所做的那些事情)之间的关系,一般适用于小型项目或大中型项目的模块级需求分析,对大中型项目的整体需求分析,实际上是一个非常复杂、有机结合的多个过程的系统,以后有机会我们再探讨。

Web服务器端技术 ,

Windows下AMP平台配置FastCGI方法(以xampp为基础)

2009年2月13日

听小韩聊PHP项目开发(1)–开题的话

2008年12月28日
本文章为 听小韩聊PHP项目开发 系列中的第1 篇(共3篇)

PHP是一个轻盈的、快捷的和强大的网站程序解决方案,它良好的完成了分析请求并对服务器资源进行调用的工作。

PHP是目前网上最流行的Web开发语言之一,据TIBOE的世界编程语言统计来看,从2001年到2008年,PHP的排行最低为10名,人数比例为1.37%,最高为第4名,比例为11.45%,你可以点击这里链接来查看此信息。

同时,PHP也在快速的发展中,从最早期的处理表单的CGI程序,逐渐增加特性,它已经成长为一个完善的面向对象的编程语言,同时内置和扩展库提供了大量的使用函数集,你可以使用这些函数集完成大量的常见工作。PHP有基本完善的面向对象语法,你可以使用大部分面向对象的概念,来实现各种设计模式和代码组织,以帮助你完成大型项目。

基于这样一些原因,在一段时间之前,我开始尝试使用PHP进行Web开发,然而最早开发的不是常见的网站,而是B/S的应用程序,继而又开发了一些网站,在这个过程中,我尝试了各种框架,也学着去评估效率,可维护性和可扩展性等多个因素,并予以实现在各个项目中。

我在进行PHP项目的开发中,逐渐总结了一些心得,包括PHP语言本身,但更多的是在项目中来看待PHP的开发,项目开发是一个很有趣的事情,在此,我们不仅要考虑功能的实现,还要考虑更多的诸如可扩展性、健壮性、与团队的合作等事情,这些经验会逐步和你们探讨和交流,这个专题正是基于此而撰写的。

这个专题,我的计划是总体由浅入深,而在具体的文章排序上不拘泥于顺序,而更像我的笔记,连载长度和时间也没有约束,所以建议您能够订阅我的RSS来获得最近的更新。

韩国峰
2008-12-28

Web服务器端技术 ,

EMAIL到你的Web程序–有趣的Email2HTTP

2008年9月12日

大家一定都体验过通过Email使用Web程序吧,什么?你还没有?那么一定是你不记得了。

Flickr可以通过Email上传文件,Google Doc可以通过Email发送文件到指定收件箱从而完成文档的转换,这些都是通过Email使用Web的例子,如果这些你都没有试用过,那么你也许用到过彩信发表照片吧,在饭否、叽歪这样的微博客网站,都是对用户体验很好的例子。

阅读全文…

Web服务器端技术 , ,