PHP5研究室 - 国内Android用户的第一选择! http://www.phpv.net/ 为Android手机提供免费应用软件,ROM,免费游戏,破解刷机,汉化工具! 同时为Android开发者提供交流平台. Tue, 16 Jan 2018 19:41:58 +0000 Chiron ver1.0 zh-cn hourly 1 高效编程所需要做的14件事 http://www.phpv.net/html/1686.html http://www.phpv.net/html/1686.html#comment Fri, 17 Apr 2009 12:24:50 +0000 抽烟的蚊子 http://www.phpv.net/html/1686.html
  • 计划(Plan)

    所谓Plan,其实就是对应于编程中的“设计”阶段,当然,这里的Plan并不像设计那样重量级。它要求我们程序员在正式编程前至少要考虑一下下面的问题:

    • 你这个程序,工具或是项目的目的,究竟是用来干什么的。你只有知道做什么,要达到什么样的目的,你才能做得对,做得好。
    • 需要有什么样的功能。需要你给出来个功能列表。这样可以保证我们不会遗露了什么。
    • 准备好一些技术难题的前期调查和解决方案。不要等到开始编程的时候才去想。

    下面这你因为有“Plan”而得到的好处:

    • 你能够清楚地明白你要做的东西长什么样?
    • 你能清楚知道你要开发的东西要干些什么事?
    • 你能够在开发过程中解决你所有可能发生的难题。
  • 使用伪代码

    伪代码是一个非常不错的方式,让你可以看到你要写的程序长什么样?根据 维基百科(Wikipedia),伪代码被写定义成这样:

    伪代码是一个紧凑和非正式的从高层描述一个计算机编程算法的结构约定。其主要是为了让人阅读而不是让计算机执行。典型的伪 代码一般会忽略那些算法中不需要人去关心的细节。比如:变量声明,系统调用,或是子程序。在伪代码中,编程语言被自然的人类语言所增强而放大,从而,更方 便,更紧凑。

    一些人并不喜欢伪代码,因为他们并不相把同样的代码写两遍,一遍是伪代码,一遍是真代码。其实,这是可以理解的,因为两个copy的东西是比较不好 维护的。但是我想,这是可以权衡的,如果的算法很简单,那么就不需要伪代码了,如果你的算法比较复杂,比较绕,那么,有一个伪代码提纲挈领将会是一件非常 不错的事情,因为他有利于让别人从一个简单的文档来了解一个复杂的算法或系统。这就好像一个电线的布线图一样,你可以很容易地通过一个简单的文档从复杂的 实现中找到头绪。

  • 书写清楚的注释

    请在你的代码中书写清楚的程序注释。当然,注释不是越多越好,注释应该是简明扼要的,如果你的程序足够地清楚简单,那么注释就会显的多余。另外,注释应该是注释“原因,理由,目的”,而不是注释“是什么”,在“酷壳”的另一篇文章《惹恼程序员的十件事》中,有一条就是关于坏的注释是多么的另个讨厌。

  • 使用自动的编辑工具

    自动的编辑工具有很多,比如 Typinator, 这是一个可以通过设定一些替代的简单代码来实现重复语句的快捷插入,比如你自己的签名、常用的语句等等,通过它可以设定替代的简短代码。还有其它一些代码 自动完成的工具,比如一些VC的插件,还有像Source Insight这样的东西。别小看这一点点时间,如果你每天都在写代码的话,今天一点点,明天一点点,将会为你省出很多的时间。

  • 减少代码

    减少代码的数量,坚持DRY(Don’t Repeat Yourself) 和KISS(Keep It Simple & Stupid) 原则。这样可以有交物减少代码的复杂度,提高程序的易读性和可维护性,同时也能增加代码的质量。

  • 代码重用

    DRY (don’t repeat yourself) 原则就是告诉我们需要重用现有的代码。这样,你才能够站在巨人的肩膀之上,从而可以更多的关注和自己所要处理业务的逻辑。编程的最高境界就是写出来的代码是可能被重用的,重用和泛型这是编程里始终在追求的目标。

  • 代码重构

    一些老的代码可能已经不合时宜了,比较以前老的C++的STL库在多线程下可能会出现很多问题。所以,我们自己的代码也是一样的,每过一段时间,我 们需要把这些代码回收再利用,这就是软件的重构。重构代码所追求的并不是要提供更多的功能,而是让老的代码更有生命力,让老的代码跟上时代,更具扩展性, 灵活性。

  • 使用设计模式

    设计模式是一种从代码级解决某一些问题的方法论。这个世界上有很多很多的设计模式,比如MVC,单实例,工厂,观察者等等,等等。使用好的设计模式可以让你的代码更具重用和扩展性。关于设计模式,请参看本站的另一篇文章《101个设计模式

  • 使用程序框架Framework

    Frameworks 是一份给程序员的礼物,他们帮助你完成了很多很细节的事情,他们有可能是一个lib库,你需要进行简单的拼装,一个几乎完成了的软件框架就已形成。这是一 个能够给开发工作提速的东西。只要上网随便搜一搜,你可以看到太多太多的框架了。形形色色,几乎都是开源社区贡献的。

  • 泛型编程

    如果抽像出一些程序中相似的东西,然后把这些相似的东西用一个标准的东西实现,这也是编程所追求的最高境界之一,像诸如C++中的STL之类的东西就是此类东西的最佳体现。灵活之及,几乎都快放之四海皆准了。

  • 使用开源的代码

    这个世界上有太多太多开源的代码了。学会利用他们可以让你更节省时间和精力,因为我们完全没有必要把相当的东西实现若干次,学会使用开源的代码不但是一个学习的过程,同样也是一个增加编程效率的事情。

  • 完善开发环境

    开发环境非常重要,因为好的开发环境可以让你事倍功半。他们可以让你不需要关注别的东西,比如,我曾看过某程序员在调整编辑器的字体和高亮上花费了不少工夫。是的,这是值得肯定了,只有把开发环境变得舒服,才能让自己更好的编程。

  • 使用调试器

    学会使用调试器来调试代码,单步跟踪,变量值跟踪,内存,堆栈等等。熟练地使用调试器可以让你更好的查找程序的问题,以得到最优的代码。

  • 使用版本管理工具

    版本管理工具应该是任何程序员都应该要去学会使用的东西,特别在一个团队中,如何管理程序的不同版本,如何维护,存放代码,版本管理工具绝对是开发过程中不可少的东西。其意义绝对不只代码备份和共享那么简单。下面是一些开源的管理管理工具:GitSVNCVSBazaar

  • ]]>
    SVN分支和合并 http://www.phpv.net/html/1676.html http://www.phpv.net/html/1676.html#comment Sun, 08 Mar 2009 17:42:19 +0000 抽烟的蚊子 http://www.phpv.net/html/1676.html 项目代码,因为分支是主干的廉价拷贝(相当只是提交了一次主干版本,增加了一个版本号, 并没有取出版本库作镜像拷贝),所以你可以放心建立很多分支版本。不过 Subversion不支持跨版本库的拷贝,当使用svn copy时你只能在同一个版本库内操作。tags目录存放trunk某个的快照,比如说release-1.0即trunk处于1.0版本时的快照。

    使用svn来作团队的代码管理,那么分支和合并将是非常常用的操作。下面是一个简单的示例。

    1. 创建分支。这里假设你要负责一个叫theme的项目,分支号1.7.2。

       1. #这里的localhost是svn服务器地址
       2. svn copy -m "1.7.2 - theme" svn://localhost/www/trunk svn://localhost/www/branches/branch1.7.2-theme
       3. svn co svn://localhost/www/branches/branch1.7.2-theme

    2. 从trunk中merge到分支。忙了一个星期终于开发完了,但是开发期间trunk版本有过改动,部署上线前你需要合并trunk的代码。

       1. #branch1.7.2-theme是分支目录,注意不可以进到分支子目录
       2. cd branch1.7.2-theme
       3. #前面的12972是开分支之前trunk的版本号,后面的12991是merge时trunk的版本号
       4. svn merge -r 12972:12991 svn://localhost/www/trunk

    如果有冲突选择p(postpone),merge完了之后使用svn st|grep ^C查看冲突文件,然后比对修改冲突文件。解决冲突后再check in ,信息写上执行的merge操作。

       1. svn ci -m 'svn merge -r 12972:12991 svn://localhost/www/trunk'

    3. 从分支merge到trunk。上线测试完毕,你很幸运,一切都如预期正常,这时就要将分支回归trunk,将trunk更新到最新。

       1. #先从trunk checkout一份新鲜的代码,然后cd到该版本目录下
       2. svn co svn://localhost/www/trunk
       3. cd trunk
       4. #12973是分支开始的版本号,13006是分支结束的版本号
       5. svn merge -r 12973:13006 svn://localhost/www/branches/branch1.7.2-theme

    如步骤2一样解决冲突,解决冲突后再check in,信息写上执行的merge操作。

       1. svn ci -m "svn merge -r 12973:13006 svn://localhost/www/branches/branch1.7.2-theme"

    相关的手册可以参阅svn文档,电子版点这里下载。 ]]>
    马化腾关于产品设计与用户体验的培训 http://www.phpv.net/html/1661.html http://www.phpv.net/html/1661.html#comment Fri, 09 Jan 2009 13:36:22 +0000 抽烟的蚊子 http://www.phpv.net/html/1661.html 昨天听了pony在峰会上的讲座,收获颇丰,晚上回家后把记录的笔记整理了一下,先放上来和大家分享一下。整理时间较短,如有不周全之处,大家谅解:)

    背景:pony是公司的首席体验官、首席产品经理。这次在产品峰会上pony将自己平时经验的积累与大家交流,体验较细。这次分享研发管理部,设计中心整理了些材料。主要的案例是qqmail和qq影音的内容。以此为demo来讲解。

    pony的讲解主要分为三大部分:产品设计、产品运营、交互设计。
    在开场首先提到,互联网同类产品竞争激烈,只有抓住用户的心才能持续走下去。产品要赢得用户的心,要从一些小的点来赢得用户。

    第一部分:产品设计
    这个部分,感受最深的是两个词:核心能力、口碑。这部分还着重提到了pony对产品经理素质、开发人员心态的期望。

    核心能力
    任何产品都有核心功能,能帮助到用户,解决用户某一方面的需求,如节省时间、解决问题,提升效率等等。
    很 多产品经理对核心能力的关注不够,不是说完全没有关注,而是没有关注到度。核心能力不仅仅是功能上也,也包括性能上的。对于技术出身的产品经理,特别是做 后台出来的,对于性能的关注,如果自己有能力、有信心做到对核心能力的关注,肯定会渴望将速度、后台做到极限。现在很多产品都没做好,一抓问题一大堆。 如,前阵子网页速度优化,好多东西可以优化,一下提速好多,之前不知道都做什么去了。之前用户忍受了很久,同时浪费时间、浪费我们的资源。不抓,都没人 理,很说部过去。要在性能方面放入更多精力。

    谈到核心的能力,首先要有技术突破点。如做影音的时候,不是要做人家有我也有的东西。以前公司做的你有我有的东西,总是排在第二第三,虽然也有机会,但缺乏第一次出来亮相失去用户的认同感。
    第一要关注你的产品的硬指标,在设计和开发的时候要考虑到外部会将对它与竞争对手做评测。如播放能力,占用内存。qq影音的核心性能和速度直接超越暴风影音。这样就能看到用户很多的好评和口碑。所以之后如果qq影音不出大问题,发展的势头将会很好。

    硬指标评测cpu占用、高清加速,当时也有很多发展方向,如网络播放啊、交流啊、分享啊,也是思路。现在都砍掉,就是要做播放器,是用户的需求,纯用户需求不需要多少钱的。高清的,并不是很多人需要的,但是是高端用户的需求(这个后面口碑创造会再提到)。只有硬指标满足了,用户说,我这个破机器,暴风影音不能放,qq影音能放。这句话说出来,这样口碑就出来了。用户知道你行,差异化出来了。口碑要有差异性

    核心能力要做到极致。要多想如何通过技术实现差异化,人家做不到,或者通过半年一年才能追上来。
    如, 用户总评论qq的时候说用qq唯一的理由是传文件快,有群。于是这些就是我们的优势,那我们就要将优势发挥到极致。我们需要更加深入的去想,要想到要不要 做传输速度、中转啊。离线传文件在邮件体现就是一个中转站,超大文件,也不难,就是要去做。产品部门很快的去做,去测试。用户用的量也不一定大,但几个月 用一次,口碑就来了。用户会说,我要传大文件,找了半天找不到可以传的地方,万般无赖之下用了很烂的qqmail,居然行了。于是我们的口碑就来了。做了 很多测试、逐步放量,看变化,因为到期就删掉,成本也没提升多少。

    要做大,要考虑到如何做到极致让人家想到也追不上,我们这么多年在idc上的功力不能浪费,需要我们去做。高速上传、城域网中专站,支持高速地上传……,又 发现问题,如不在邮件,在im做怎么体验,这个我们在后面要逐步考虑到做起来。我们的目的是要让用户感到超快、飞快,让用户体验非常好。这些都需要大量技 术和后台来配合。

    产品的发展都需要产品经理来配合。现在我 们产品经理有是做研发出身的不多。而很多产品和服务是需要大量技术背景的,目前我们希望的产品经理是非常资深的,做过前端、后端开发的技术研发人员晋升而 来的,刚毕业的人员来做产品经理很人担心。好的产品最好交到一个有技术能力的、有经验的产品人员手上,会让大家更加放心。如果产品人员太烂,让很多兄弟陪 着干,结果发现方向错误是非常浪费和挫伤团队士气的。
    产品 最难的是订优先级和先后次序。要看哪个是用户最核心的。功能好不好不是说有用户用了,用量多少了,写个报告统计下流量证明是好。这个是很错误的,好不好要 看用户是不是要用这个功能,用户要用的实时出现。腾讯很多产品经理的激情还不够,做出来的产品比较大路货。虽然挑剔不出很不对的东西,但放出去用户也没有 感觉,最后就不了了之。pony有时候很痛心,希望大家在产品设计之初就想的透彻一点。产品经理需要投入更多的关注度,关注度不一样,结果出来的很不一样。

    口碑

    做产品要做口碑,要关注高端用户、意见领袖关注的点。以前的思路是抓大放小,满足大部分小白用户的需求。但是高端用户这块是真正可以拿口碑的。

    如何提高口碑,看最高端用户的关注,这个是在基础功能比较好的情况下考虑。如邮件搜索啊,rss啊,这些是很炫的用户会在博客和论坛里面提及的。做起来也不难,在有能力的情况下保证。在产品已经成型的情况下,要考虑到,对高端用户的心态要不一样。如果想要获得高端用户的口碑,还需要在产品的设计上大气些。如,让用户在我们的qqmail上使用别的邮箱的地址,而不带任何自己qqmail的尾巴。之前我们做的时候不会自动保存别的邮箱的地址,自己心里打个小九九,让别人不方便使用外部邮箱地址,好使用我们的。这些小九九,高端用户都是看的出来,反倒不好。所以要改掉,要做到真正的方便到用户。 改变用户习惯要让他信任你,改变有过程的,需要通过我们的努力让用户慢慢改过来。如,关闭数字帐号,发现很多bug,拍拍都不知道改。如,独立密码,之前不是双密码,而是改整体密码。

    需要满足高端用户,让他不要怀疑你、bs你。如浏览器到兼容,可能你会考虑很多浏览器的覆盖率不高而不去做,但在高端用户来看,这是个态度问题,如果你的产 品连这个都没考虑,其他的我就都怀疑了。你这个产品团队的意识好不好。再如同文件夹是否对齐,是否会引起杀毒软件的报警,都是小事但要关注。
    个性化服务,并不是大众化服务,也是拿口碑的。

    一个产品在没有口碑的时候,不要滥用平台, 如要im带呀,投入营销资源呀,要marking联系pr公司投放广告呀,广告位提要求……等着人家砍,想一半也够了。产品经理精力好像分布的很好50% 产品、30%营销、20%……。如果你在基础处控制的好,也可以。但90%的时候第一点都做不好。如果你的实力和胜算不到70-80%,那么把精力放在最 核心的地方。在已经获得良好口碑,处于上升期的产品才考虑这些。

    产品经理关注最最核心、获得用户口碑的战略点,如果这块没做透,做营销只是告诉用户过来,失望,再花更多的精力弥补,是得不偿失的。当用户没有自动在增长 (用户会主动给朋友推荐来使用我们的产品的时候),看着用户的增长,否则不要去打扰用户,否则可能是好心办坏事。这个时候,每做一件事情,每加一个东西要 很慎重的考虑,真的是有建设性的去增加产品的一个口碑。当用户口碑坏掉后,再将用户拉回来很难。

    加 功能,在管理控制功能上也要有技巧。在核心功能做好后,常用功能是要逐步补齐的。产品在局部、细小之处的创新需要永不满足。作为一个有良好口碑的产品,每 加一个功能都要考虑清楚,这个功能给10%的用户带来好感的时候是否会给90%的用户带来困惑。如果有冲突的要聪明点,分情况避免。每个功能不一定要用的多才是好,而是用了的人都觉得好就是好。

    做产品开发的时候需要有较强的研发机制保证,这样可以让产品开发更加敏捷更加快速。 有些需求,提一下都可以得到很快反应。qqmail也会每天排好规划,为什么能很快反应,如文件加锁。有些产品做个东西写ppt、做汇报……,人家顺手就 做了。很多产品不敏捷,大家要敏捷点、就算是大项目也要灵活。不能说等3个月后再给你个东西看,这个时候竞争对手都不知道跑到好远了。

    开发人员的心态要关注产品,不要是公事公办的态度。你要知道用户、同行会关注你的产品,在这种驱动下开发人员要自动去完成。不能说什么都要产品做好后,流水线样的送过来我才做。开发人员要参与,40-50%左右的产品最终体验应该是由开发人员决定的。产品人员不要嫉妒有些工作是是开发人员设计的,只有这样才是团队共同参与的。如果都是产品想的就完蛋了,那么这个team做这个产品没有什么机会,必然会产生产品迭代慢的效果这样一个格局太不行了。

    运营式管理

    这个部分感受最深的一个词:天天用。这部分还谈到了pony眼中产品经理的一些基本要求。
    我们的产品不是单机版,需要有强的用户感和技术功底外,很重要的是服务。我们要关注很多很复杂的内容,如架构啊,应用啊,产品需要有更好的架构,这个是需要花很多精力,常态下可能看不出来。所以需要高层从kpi上考虑。这个是考功力,谁做的好,总办领导是看得到的。设计的好的架构不会手乱脚乱。如把核心的东西做成组件模块分发。

    发现产品的不足,最简单的方法就是产品天天用。 天天去看,去论坛,去博客、去订阅。产品经理要敏感点,找出你的产品不足之处。有的产品经理说找不出来很奇怪,上线的时候坚持三个月天天用,问题是有限 的,一天发现一个,解决掉,这样慢慢的已经开始逼近你那个很有口碑的点了。不要因为工作没有技术含量就不去做,很多好的产品都是靠这个方法做出来的。对于 高层来说,不仅仅是安排下面的人去做就可以了,一定要自己做。这些都不难,关键要坚持。意识要提高。你要做到每个周末,都心痒痒要去做。心里一定要想着,这个周末不试,肯定出事。这样坚持,到一个产品基本成型,就可以去看下个产品了。

    从 哪个地方找,论坛啊、博客啊,rss订阅啊。高端用户不屑于去论坛提,在博客提,需要产品经理自己去追出来。如qqmail、影音的产品经理自己去查、去 搜,然后主动和用户接触,解决,有些确实是用户搞错了,有些是我们的问题。产品经理心态要很好,希望用户能找出问题我们再解决掉。哪怕再小的问题解决了也 是完成一件大事。有些事情做了,见效很快。运营方面要天天去看的,产品经理要关注多个方面,比如说你的产品慢,用户不会管你的idc烂或者其他原因,只是 知道你慢。产品经理要全面,服务器端哪个方面的问题能找出来。跟踪用户定位问题。如果pony都能搜索到的问题,没看到产品经理出现,那么就是你没做到位。


    交互设计

    交互要求我们细致,视觉简洁清爽。

    产品经理要想到自己是个挑剔的用户,想像自己是个笨用户,复杂的看不懂。
    产品人员的精力有限,交互内容很多,所以要抓最常见的一块。流量、用量最大的地方都要考虑。规范到要让用户使用的舒服。要在感觉、触觉上都有琢磨,有困惑要想到去改善。如鼠标少移动、可快速点到等等。
    像邮箱的一个按钮“返回”放在哪儿,上线测,放右边还是左边,大家都会多放琢磨,怎么放更好,并上线尝试,现在的方案折中比较好。如输入邮箱密码出错,输入框内的内容select上,不用用户清楚可以直接输出。这些都是对用户体验的优化。

    如对同个用户发信,在此用户有多个邮箱的情况下会默认选最近用的一个帐号。这些需求都小,但你想清楚,用户就会说好,虽然用户未必说的出好在哪儿。

    产品的使用要符合用户的习惯,如写邮件的时候copy东西,更多人习惯用键盘来操作。虽然有些技术难度,但也可以解决。交互,对鼠标反馈的灵敏性,便捷性。

    不强迫用户,如点亮图标。如qqmail,不为1%的需求骚扰99%的用户
    操作便利,如qq音乐,新旧列表,两者都要兼顾到,如qq影音的快捷播放,从圆形到方形,最后因为影响性能而放弃。

    美术、淡淡的,点到即止,如qqmail,qqmail在ui上的启发,不用太重也能做的很好。后来用在大量的产品,如hummer、影音。有图案和简洁不矛盾。

    重点突出,防止不必要的低龄化,还提到了一些内容,如产品成功关键点等等,这些在pony的ppt上有,没有记下来,大家可以在之后腾讯峰会吧(http://km.oa.com/group/forum)直接看pony的ppt。

    最后pony谈了一下有些产品的态度问题——态度很好,不解决问题。只做表面功夫,与其花一段时间写个长长的报告,不如实实际际的去解决问题。
    外部也有很多优秀的产品可以学习,学习不是学皮毛,学样子,要学会。
    外部可以学习的优秀产品,web类的,google、yahoo、facebook、apple,非web类的没有记录下来。

    总结一下:
    1、核心功能要做透,做的人家追不上,自己的优势要尽量的发挥;
    2、产品口碑要建立,要关注高端用户,要调整自己心态;
    3、敏捷、快,产品迭代要快,快速实现、快速响应,要做到真正的迭代;
    4、产品人员要全面,要能找出核心需求,要关注技术(架构、服务是不是好),要关注产品(天天用),要关注用户(还需要出去寻找问题并解决);
    5、开发人员心态要好,要有参与感,不要被动的等;
    6、交互设计简洁,关注要点,当自己是个挑剔的、笨的用户;
    7、 想办法利用公司的资源,如pony等人都是大家的公共资源,要争取到pony对自己产品的关注,会给你的产品带来很多好的指导和创意。(这个不是pony 说的,是后来jeff提到的,不过很实在,pony做过这么多的产品,有这么好的产品感觉,如果给你的产品提出建议,是对产品很大的帮助) ]]>
    在 PHP 中养成 7 个面向对象的好习惯 http://www.phpv.net/html/1641.html http://www.phpv.net/html/1641.html#comment Thu, 20 Nov 2008 10:47:54 +0000 抽烟的蚊子 http://www.phpv.net/html/1641.html 如果您尚未打算用 OO 原则创建应用程序,则使用 PHP 的面向对象(OO)的语言特性,这 7 个习惯将帮助您开始在过程编程与 OO 编程之间进行转换。

    在 PHP 编程早期,PHP 代码在本质上是限于面向过程的。过程代码 的特征在于使用过程构建应用程序块。过程通过允许过程之间的调用提供某种程度的重用。

    但是,没有面向对象的语言构造,程序员仍然可以把 OO 特性引入到 PHP 代码中。这样做有点困难并且会使代码难于阅读,因为它是混合范例(含有伪 OO 设计的过程语言)。使用 PHP 代码中的 OO 构造 — 例如能够定义和使用类、能够构建使用继承的类之间的关系以及能够定义接口 — 可以更轻松地构建符合优秀 OO 实践的代码。

    虽然没有过多模块化的纯过程设计运行得很好,但是 OO 设计的优点表现在维护上。由于典型应用程序的大部分生命周期都花费在维护上,因此代码维护是应用程序生命周期的重要部分。并且在开发过程中代码维护很容易 被遗忘。如果在应用程序开发和部署方面存在竞争,那么长期可维护性可能被放在比较次要的地位。

    模块化 — 优秀 OO 设计的主要特性之一 — 可以帮助完成这样的维护。模块化将帮助封装更改,这样可以随着时间的推移更轻松地扩展和修改应用程序。

    总的来说,虽然构建 OO 软件的习惯不止 7 个,但是遵循这里的 7 个习惯可以使代码符合基本 OO 设计标准。它们将为您提供更牢固的基础,在此基础之上建立更多 OO 习惯并构建可轻松维护与扩展的软件。这些习惯针对模块化的几个主要特性。有关独立于语言的 OO 设计优点的更多信息,请参阅 参考资料

    7 个优秀 PHP OO 习惯包括:

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

    保持谦虚

    保持谦虚指避免在类实现和函数实现中暴露自己。隐藏您的信息是一项基本习惯。如果不能养成隐藏实现细节的习惯,那么将很难养成任何其他习惯。信息隐藏也称为封装

    直接公开公共字段是一个坏习惯的原因有很多,最重要的原因是让您在实现更改中没有应有的选择。使用 OO 概念隔离更改,而封装在确保所作更改在本质上不是病毒性(viral)更改方面扮演不可或缺的角色。病毒性 更改是开始时很小的更改 — 如将保存三个元素的数组更改为一个只包含两个元素的数组。突然,您发现需要更改越来越多的代码以适应本应十分微不足道的更改。

    开始隐藏信息的一种简单方法是保持字段私有并且用公共访问方法公开这些字段,就像家中的窗户一样。并没有让整面墙都朝外部开放,而只打开一两扇窗户(我将在 “好习惯:使用公共访问方法” 中介绍访问方法的更多信息)。

    除了允许您的实现隐藏在更改之后外,使用公共访问方法而非直接公开字段将允许您在基本实现的基础上进行构建,方法为覆盖访问方法的实现以执行略微不同于父方法的行为。它还允许您构建一个抽象实现,从而使实际实现委托给覆盖基本实现的类。

    坏习惯:公开公共字段

    在清单 1 的坏代码示例中,Person 对象的字段被直接公开为公共字段而非使用访问方法。虽然此行为十分诱人,尤其对于轻量级数据对象来说更是如此,但是它将对您提出限制。


    清单 1. 公开公共字段的坏习惯
    <?php
    class Person
    {
    public $prefix;
    public $givenName;
    public $familyName;
    public $suffix;
    }

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

    echo($person->prefix);
    echo($person->givenName);

    ?>

    如果对象有任何更改,则使用该对象的所有代码也都需要更改。例如,如果某人的教名、姓氏和其他名字被封装到 PersonName 对象中,则需要修改所有代码以适应更改。

    好习惯:使用公共访问方法

    通过使用优秀的 OO 习惯(参见清单 2),同一个对象现在拥有私有字段而非公共字段,并且通过称为访问方法getset 公共方法谨慎地向外界公开私有字段。这些访问方法现在提供了一种从 PHP 类中获取信息的公共方法,这样在实现发生更改时,更改使用类的所有代码的需求很可能变小。


    清单 2. 使用公共访问方法的好习惯
    <?php
    class Person
    {
    private $prefix;
    private $givenName;
    private $familyName;
    private $suffix;

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

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

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

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

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

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

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

    public function getSuffix()
    {
    return $suffix;
    }

    }

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

    echo($person->getPrefix());
    echo($person->getGivenName());

    ?>

    乍看之下,这段代码可能会完成大量工作,并且实际上可能更多是在前端的工作。但是,通常,使用优秀的 OO 习惯从长远来看十分划算,因为将极大地巩固未来更改。

    在清单 3 中所示的代码版本中,我已经更改了内部实现以使用名称部件的关联数组。比较理想的情况是,我希望拥有错误处理并且更仔细地检查元素是否存在,但是本例的目 的在于展示使用我的类的代码无需更改的程度 — 代码并没有察觉到类发生更改。记住采用 OO 习惯的原因是要谨慎封装更改,这样代码将更具有可扩展性并且更容易维护。


    清单 3. 使用不同内部实现的另一个示例
    <?php
    class Person
    {
    private $personName = array();

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

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

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

    public function getGivenName()
    {
    return $this->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->setPrefix("Mr.");
    $person->setGivenName("John");

    echo($person->getPrefix());
    echo($person->getGivenName());

    ?>







    做个好邻居

    在构建类时,它应当正确地处理自己的错误。如果该类不知道如何处理错误,则应当以其调用者理解的格式封装这些错误。此外,避免返回空对象或者状态无 效的对象。许多时候,只需通过检验参数并抛出特定异常说明提供参数无效的原因就可以实现这一点。在您养成这个习惯时,它可以帮您 — 和维护代码或使用对象的人员 — 节省很多时间。

    坏习惯:不处理错误

    考虑清单 4 中所示的示例,该示例将接受一些参数并返回填充了一些值的 Person 对象。但是,在 parsePersonName() 方法中,没有验证提供的 $val 变量是否为空、是否是零长度字符串或者字符串是否使用无法解析的格式。parsePersonName() 方法不返回 Person 对象,但是返回 null。使用这种方法的管理员或程序员可能会觉得很麻烦 — 至少他们现在需要开始设置断点并调试 PHP 脚本。


    清单 4. 不抛出或处理错误的坏习惯
    class PersonUtils
    {
    public static function parsePersonName($format, $val)
    {
    if (strpos(",", $val) > 0) {
    $person = new Person();
    $parts = split(",", $val); // Assume the value is last, first
    $person->setGivenName($parts[1]);
    $person->setFamilyName($parts[0]);
    }
    return $person;
    }
    }

    清单 4 中的 parsePersonName() 方法可以修改为在 if 条件外部初始化 Person 对象,确保总是获得有效的 Person 对象。但是,您得到的是没有 set 属性的 Person,这仍然没有很好地改善您的困境。

    好习惯:每个模块都处理自己的错误

    不要让调用方凭空猜测,而是对参数进行预先验证。如果未设置的变量无法生成有效的结果,请检查变量并抛出 InvalidArgumentException。如果字符串不能为空或者必须为特定格式,请检查格式并抛出异常。清单 5 解释了如何在演示一些基本验证的 parsePerson() 方法中创建异常以及一些新条件。


    清单 5. 抛出错误的好习惯
    <?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.");
    }


    }
    }
    ?>

    最终目的是希望人们能够使用您的类,而不必了解其中的工作原理。如果他们使用的方法不正确或者不是按照期望的方法使用,也不需要猜测不能工作的原因。作为一个好邻居,您需要知道对您的类进行重用的人并没有特异功能,因此您需要解决猜测的问题。







    避免看到美杜莎

    在我最初了解 OO 概念时,我十分怀疑接口是否真正有帮助。我的同事给我打了个比方,说不使用接口就好像看到美杜莎的头。在希腊神话中,美杜莎是长着蛇发的女怪。凡是看了她 一眼的人都会变成石头。杀死美杜莎的珀尔休斯通过在盾上观察她的影子,避免了变成石头而得以与她对抗。

    接口就是对付美杜莎的镜子。当您使用一个特定的具体实现时,代码也必须随着实现代码的更改而更改。直接使用实现将限制您的选择,因为您已经在本质上把类变成了 “石头”。

    坏习惯:不使用接口

    清单 6 显示了从数据库中装入 Person 对象的示例。它将获取人员的姓名并返回数据库中匹配的 Person 对象。


    清单 6. 不使用接口的坏习惯
    <?php
    class DBPersonProvider
    {
    public function getPerson($givenName, $familyName)
    {
    /* go to the database, get the person... */
    $person = new Person();
    $person->setPrefix("Mr.");
    $person->setGivenName("John");
    return $person;
    }
    }

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

    echo($person->getPrefix());
    echo($person->getGivenName());

    ?>

    在环境发生更改之前,从数据库中装入 Person 的代码都可以正常运行。例如,从数据库装入 Person 可能适用于第一个版本的应用程序,但是对于第二个版本,可能需要添加从 Web 服务装入人员的功能。其实,该类已经变成 “石头”,因为它在直接使用实现类并且现在能做的更改十分有限。

    好习惯:使用接口

    清单 7 显示了一个代码示例,在实现了加载用户的新方法后并没有进行更改。该示例显示了一个名为 PersonProvider 的接口,该接口将声明单个方法。如果任何代码使用 PersonProvider,代码都禁止直接使用实现类。相反,它就像是一个实际对象一样使用 PersonProvider


    清单 7. 使用接口的好习惯
    <?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->setPrefix("Mr.");
    $person->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->getPerson("John", "Doe");

    echo($person->getPrefix());
    echo($person->getGivenName());
    ?>

    在使用接口时,尝试避免直接引用实现类。相反,使用对象外部的内容可以提供正确的实现。如果您的类将装入基于某些逻辑的实现,它仍然需要获取所有实现类的定义,并且那样做也无法取得任何效果。

    您可以使用 Factory 模式来创建实现接口的实现类的实例。根据约定,factory 方法将以 create 为开头并返回接口。它可以为您的 factory 获取必要的参数以计算出应当返回哪个实现类。

    在清单 7 中,createProvider() 方法只是获取 $type。如果 $type 被设为 database,工厂将返回 DBPersonProvider 的实例。从数据库中装入人员的任何新实现都不要求在使用工厂和接口的类中进行任何更改。DBPersonProvider 将实现 PersonProvider 接口并且拥有 getPerson() 方法的实际实现。







    利用最弱的链接

    将模块松散耦合 在一起是件好事情;它是允许您封装更改的属性之一。另外两个习惯 — “保持谨慎” 和 “避免看到美杜莎” — 可帮助您构建松散耦合的模块。要实现松散耦合的类,可通过养成降低类依赖关系的习惯实现。

    坏习惯:紧密耦合

    在清单 8 中,降低依赖关系并不是必须降低使用对象的客户机的依赖关系。相反,该示例将演示如何降低与正确类的依赖关系并最小化这种依赖关系。


    清单 8. Address 中紧密耦合的坏习惯
    <?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->addressLine1 = $line1;
    }

    /* accessors, etc... */

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

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

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

    echo($addr->format("multiline"));
    echo("n");

    echo($addr->format("inline"));
    echo("n");

    ?>

    Address 对象上调用 format() 方法的代码可能看上去很棒 — 这段代码所做的是使用 Address 类,调用 format() 并完成。相反,Address 类就没那么幸运。它需要了解用于正确格式化的各种格式化方法,这可能使 Address 对象无法被其他人很好地重用,尤其是在其他人没有兴趣在 format() 方法中使用格式化方法类的情况下。虽然使用 Address 的代码没有许多依赖关系,但是 Address 类却有大量代码,而它可能只是一个简单的数据对象。

    Address 类与知道如何格式化 Address 对象的实现类紧密耦合。

    好习惯:在对象之间松散耦合

    在构建优秀的 OO 设计时,必须考虑称为关注点分离(Separation of Concerns,SoC)的概念。SoC 指尝试通过真正关注的内容分离对象,从而降低耦合度。在最初的 Address 类中,它必须关注如何进行格式化。这可能不是优秀的设计。然而,Address 类应当考虑 Address 的各部分,而某种格式化方法应当关注如何正确格式化地址。

    在清单 9 中,格式化地址的代码被移到接口、实现类和工厂中 — 养成 “使用接口” 的习惯。现在,AddressFormatUtils 类负责创建格式化方法并格式化 Address。任何其他对象现在都可以使用 Address 而不必担心要求获得格式化方法的定义。

    下一页>>




    ]]>
    产品经理们,遇到Bug请别十万火急 http://www.phpv.net/html/1619.html http://www.phpv.net/html/1619.html#comment Tue, 05 Aug 2008 22:43:02 +0000 抽烟的蚊子 http://www.phpv.net/html/1619.html


    如果你希望成为一个成功的产品经理,在遇到bug时,请不要总是立即着急的修复它。不可否认,我们在遇到问题时,总是迫不及待的想改正。然而事实上,其实根本不用那么的十万火急,理由如下:

    如果迅速解决了问题,你可能会忽略问题的根本原因。在大多数时候,每个问题都有其根本诱因。在问题刚暴露的时候,诱因一般深藏不露,有很多的可能性。笔者认为,根本诱因最可能来自于需求确认阶段。

    同样,在产品管理的其他阶段,这个理论也适用。有些问题可以很容易就找到根本诱因,但产品开发的真正挑战来自各种不稳定的因素。例如,有时候一款漏洞百出的产品在上线之初,只暴露了冰山一角:一个很小的Bug,似乎十分容易解决。另一个例子,开发过程中,团队成员对各项功能的优先级有争议时,靠“民主投票”来做决策,而忘了引发争议的源头:对产品远景、战略及计划缺乏共识。


    医生治疗的是疾病,而不是治疗症状(译注:治疗感冒或支气管炎,而非咳嗽)。医生的任务不是治标,而是治本。对于PM而言,道理一模一样。


    让问题暴露一段时间,或许是让大家认识到其严重性的唯一方法。很多父母都会说,他们的小孩吃一堑才长一智——例如,不去摸滚烫的炭炉——若小孩自己被炭炉烫伤一次后,他们自然会明白那东西是摸不得的。在产品开发过程中,存在着同样的道理。当你试图请同事修改或改进某功能时,你需要解释这是为了什么。如果大家不明白改进的意义,自然会无动于衷。


    举个例子,假设你发现团队使用的需求管理软件存在着很大的问题,假如你希望马上修改它,或许得花大量精力去告诉大家修改的意义,还得制作demo 进行 说明。但如果让这个需求管理软件继续运转一段时间,让它自己暴露出弱点,可能是一种更好的办法。因为需求管理软件的问题,在新产品上线前,你会发现有些最初制定的需求并没有实现。此时,你可以告知大家这些遗漏的需求,但是不需要为之耽误了上线时间。如果你是正确的,要不了多久,大家就会意识到,因为使用了那个糟糕的需求管理软件,才导致产品出现一些无法挽救的Bug。

    提醒,本方法需十分小心的使用。作为PM,就算你本意是为了让同事们更透彻的看清问题,也不能忘了你是该产品最终成败的负责人。所以多数情况下,使用本方法时,最好选择小项目来作为案例。

    问题可能没有你想象中那么严重。每次问题出现的时候——产品暴露了Bug,用户发出抱怨,会议上的争论——看上去总是迫切得非解决不可。于是,PM不得不暂时暂停正在进行的真正关键工作——战略、计划、用户调研——而把精力用在四处“灭火”上。

    然而,必须立即解决的Bug其实很少。同时,与PM应该着重思考的产品方向等问题比起来,这些Bug的重要性实在很低。每个Bug都有看上去万分关键的时刻,但过段时间后,它们似乎都变得无关紧要了。事实上,真正严重的Bug会迅速暴露出来。牢记这一点,会让PM把时间用在刀刃上,而不是每天都在处理危机。

    花更多的时间可以找到更完美的解决方案。若在全面了解Bug之前,就急着去为Bug寻找答案,我们通常会选择脑海中冒出来的第一个解决方案。这可能也算是一个过得去的方案,不过若我们花更多时间来分析此Bug,找到其根本诱因,甚至来一场头脑风暴,或许我们能发现更完美的解决方案。当然了,花更多时间也不一定就找得到更棒的方案,但至少,花了时间之后,得到的不会是更少的备选方案或更差的解决方案。

    下一次遭遇Bug时,请别十万火急。PM需要有战略眼光(不是战术),请先分析Bug,找到根本诱因,并衡量全局重要性,再对Bug进行解决。若不是每一次都着急解决每一个Bug,PM可以花更少的时间四处“灭火”,从而拥有更多的时间去思考产品战略——如何给用户带去更多的价值。

    本文译自,作者是Jeff Lash。

    ]]>
    写给刚刚上岗的网站技术人员 http://www.phpv.net/html/1618.html http://www.phpv.net/html/1618.html#comment Wed, 23 Jul 2008 16:03:47 +0000 admin http://www.phpv.net/html/1618.html        工作5年了,网站相关的开发工作也干了4年多。负责带领团队也好几年了。面试和带领刚工作的人也不少了。其中的优秀者不少,但是大多数都存在下面提到的几个认识误区。把这些问题提出来,希望对刚参加工作没有多久的程序员们有所帮助,少走弯路。

     

    公司招你进来,其实最重要的就是看到你的工作能力和工作态度是可以接受的。

    工作能力指你能满足他们的工作期望,或者在可接受的时间范围内,经过培训后,可以满足这个工作期望。

    工作态度指你能有些做职员的基本素质。

    这个道理应该所有人都清楚。但是到实际事情时候就经常犯迷糊。下面几点是经常会出问题的地方:

     

    1、不经测试,Review,就认为自己工作完成了。

           你的代码或者应用一旦被别人Review ,或者进行试用。这时候你代码的好坏,或者功能是否在各种场景下是否可用,都会影响你这个人在上级及同事眼里的可信任度。

           代码书写的规范,性能的高质量,各种功能在各个场景都可用,则表示你这个人是完全可信的。下次上级给你分派任务的时候,就可以给你更多的自由度来发挥。长此以往,前途和钱途自然就随手可得。

            反之,代码不规范,功能好些场景不可用。这只能让上级或同事觉得你不可信任。每次都需要处理你带来的这些问题,说恶心点就是你每次拉完大便都没擦屁股,每 次都得你的同事和上级帮你擦屁股。数次都这样后,上级或同事下次跟你沟通的时候就会觉得你这个人不可信任,一件事情必须反复多次强调,总觉得你还会作出问 题。你的信用已经非常危险了。

           你在别人眼里的信用就这样被你慢慢透支了。透支到一定程度,走人吧。整个团队的效率会因为你而变慢(每个人跟你沟通的成本都会影响到他本人的产出),你不走人谁走人。

     

    2、最短可接受的工作时限

           你有没有统计过,公司分派给你一个工作时候,上级指定的这项工作计划做多久的预计,跟你自己的预计有多大差异?

           如果你预计时间大于上级给的工作计划时间,同时上级没有增派人手进行相关工作。除了BT的领导外,那只有一种情况:上级对你的工作态度非常不满,认为你的薪水对应的工作能力不是这么点。

           对于刚工作的,更多的是你表现出来的工作能力在公司的平均工作能力之下。同时公司觉得你对工作没有表现出足够的热情。 一个能力在平均水平下面,又缺乏工作激情的人,他的前途在那里??

           如果这个人还没有表现出几个月后能达到平均水平之上的希望,为啥会留这样一个人呢?

     

    3、工作能力不等于技术水平

           我曾看到过有人抱怨说大公司的员工也不过是这技术水平, 这么简单的技术问题都不会。我自己早期也有这样想法,后来发现是不对的。

           不论大公司还是小公司,要得是解决问题的工作能力。 我的曾经手下就有好几个技术水平很牛的,但是作出来的应用却一次次返工的。为啥,工作能力这些非技术因素他们做的很不好。

           工作能力的非技术因素包括的很多: 责任心,表现就是对自己写出来的代码有一定要让人放心的责任; 沟通能力,一个典型的表现就是需求不理解或者需求不明时,及时得跟相关人沟通,而不是自己先按自己想法实现,造成代码写完后再返工的恶果等等。

           技术水平低,但是解决问题能力强的,我也碰到过一些人。 工作的能力更重要的是这些非技术的工作能力,而不是技术水平。技术人员很容易技术水平高,但是非技术的工作能力差。 这是很糟糕的。

         

     

    4、发展潜力,学习能力

          公司使用的技术不可能一直不变,一直不变的公司只能慢慢被市场淘汰。这就要求员工能不断的学习新的知识,并应用到工作中来。

          要想不会出现几年后,自己发现跳槽找个工作都没人要,赶快学习吧。

          坚持,是一个人最难做到的。 但是不坚持,那就等着灭亡吧。

     

    5、笨鸟先飞

          一个人,在公司,如果工作能力在平均线以下, 加班吧, 不要有任何幻想。

          最可怕的是自己没这个意识, 自认为自己技术水平很牛, 但是解决问题的工作能力却在平均水平线以下, 眼高手低 , 这样的人, 公司是不能留的。

     

     

    6、承诺到的事情一定要做到,不要找理由

           一件事情没有被做完,想找理由能找很多的。既然你承诺了某个时间点前完成,就不要再找各种理由推脱。

           公司同事和上级虽然可能这次接受了你的理由,但是下次呢, 慢慢的就会让你的上级,同事觉得你是一个喜欢推托的人。 感觉你干事是非常不可靠的。不知道那次就会不完成,下次谁敢再找你干事?

         可能很多人在看到我这篇博客的时候,觉得我写的很刻薄,好像都是从公司的角度欺压技术人员。很没有人情味。

            只要你不是公司的董事, 你永远是被剥削者,公司的目的就是利润最大化,这是公司存活的根本目的。作为普通的职员,要有所为的白领意识,其实就是被剥削意识。这是个适者生存的生态圈,不适用的人只能被淘汰。

            实际的公司其实有很多人情味在里面,或者同事和领导有些话不便于说出口。 这也就造成了一些技术人员被开除,还自以为如何如何? 都是没有这些意识造成的。我写这篇博客就是希望能增加技术人员的这些意识,不要犯了这些问题还自己不知道。

    ]]>
    用户不上你的网站的50个原因 http://www.phpv.net/html/1504.html http://www.phpv.net/html/1504.html#comment Fri, 21 Apr 2006 21:48:58 +0000 easy http://www.phpv.net/html/1504.html 原因如下:

    1 他们不想生产内容,他们期望的是更好的生活
    2 因为你能解决的问题是他们所没有的问题
    3 而对于他们真正的问题你却无法解决
    4 奥普拉没有提到过它
    5 他们所认识的所有人都不上你的网站
    6 你没有办法让他们窥视自己所喜欢的人
    7 他们对自己所看见的并不在乎
    8 没有哪个同事说应该上这个网站
    9 它很没趣
    10 它无法让人们开怀大笑
    11 它没有办法帮人们省下一大笔钱
    12 它没有办法帮人们节省时间
    13 没有什么让他们感到激动万分的东西
    14 它既不能拯救生命也不能拯救世界
    15 它不像赌城那样充满刺激
    16 它看上去像是花旗银行的广告,而人们憎恨它
    17 没有人排队
    18 他们又工作,有孩子,工作繁忙
    19 因为他们和美国偶像节目的选手有约会
    20 他们害怕电脑
    21 他们有了足够的朋友
    22 他们文笔不好
    23 更多的人在用Craiglist
    24  你没有告诉他们怎么去做
    25  不上这个网站,没有人会认为他是白痴
    26 它是为了怪人和白痴准备的
    27 它肯定是为了那些“电脑高手”准备的
    28 有人会盗窃他们的身份而诱拐其孩子
    29 他们不明白你的专业术语
    30 他们更擅长于让那些让你感到无能为力的事
    31 他们出生于1985年以前
    32 他们对电脑并不精通
    33 他们很害羞
    34 他们不像Yahoo, Amazon或者Ebay那样
    35 它的主页不止一屏,不像Google那样
    36 他们感觉沮丧
    37 他们不想坐在电脑面前
    38 他们尝试过使用它,但是结果一团糟
    39 他们从来就没有听过它
    40 他们有更重要的事情要做
    41 周刊更吸引人
    42 它上面写着什么”tag”,”RSS”,简直愚蠢透顶
    43 家庭和朋友需要他们
    44 他们不想过的那么沉闷
    45 他们从来没有听说过Flickr和Del.icio.us
    46 没有足够的人使用它,也没有成功的例子
    47 没有暴露图片和名人消息
    48 没有告诉他们为什么要用它
    49 它不能提供给他们爱情和性
    50 他们不想知道你想让他们做什么

    (Undersound编译)

    ]]>
    软件项目管理常见问题分析 http://www.phpv.net/html/308.html http://www.phpv.net/html/308.html#comment Wed, 08 Sep 2004 02:05:46 +0000 admin http://www.phpv.net/html/308.html 摘要:

    本文分析了软件项目管理常见问题:缺乏项目管理系统培训、项目计划意识问题、管理意识问题、沟通意识问题、风险管理意识问题、不重视项目经验的总结、项目干系人相关问题、项目团队内分工协作问题,抛砖引玉地提出了部分解决方案,提出了项目约束绳与多重目标模型。

    关键字:

    软件项目管理、问题、分析

    正文:

    目前许多软件开发公司实行了ISO质量管理体系,也有越来越多的公司通过了CMM软件成熟度相应级别认证。各软件在制定ISO质量管理体系时结合了部分项目管理的思想和技术,因此这些经过认证的公司的项目管理工作在ISO质量管理体系或CMM的帮助或约束下已有一定的规范,项目可以按照规定的过程一步一步做下去。但ISO体系注重的是质量管理(即用过程保证质量),早期更多的是针对制造业,而CMM主要是针对软件开发过程的关键过程域,都没有针对项目管理的全部范畴,如对于整体、范围、进度、人力资源、成本、沟通、风险、采购等的管理,即使有涉及到也是在专业范围内通过对过程的把握来保证各种质量要求,而在过程规定之外还需要依靠项目相关各方运用项目管理知识、工具、集体与个人的智慧来使项目管理做得更好,以保证项目在使用最少的时间、资源情况下按时保质地完成。

    最近通过几次 “项目管理知识培训”,本人系统地学习了项目管理基础和项目管理实践等课程,掌握了项目管理在系统集成方面应用所必备的知识。结合所学的项目管理知识,我们可以对照我们原来的项目管理工作中存在的常见问题,利用项目管理知识进行分析,并提出解决的方案,希望有利于大家逐步改进我们的项目管理工作。这些方案因受到本人知识和工作经验的局限,只能起到一个抛砖引玉或参考的作用。

    分析目前项目管理需要改进的问题可以从几种相关角色的角度去考虑:项目经理、项目组成员、公司管理人员、市场人员、客户等。

    问题一:缺乏项目管理系统培训

    相关对象:项目经理、管理人员

    问题说明:项目经理在项目管理方面的培训较少或不够系统。项目经理或管理人员不了解项目管理的知识体系和一些常用工具和方法,所以在实际工作中没有项目管理知识的指导,完全依靠个人现有的知识技能,管理工作的随意性、盲目性比较大。有些学员说:“听了这些课才知道项目管理原来还有这么多的学问。”例如对于如何利用工作分解结构使项目的工作范围更加明确,如何用前导图法对活动进行排序并估算项目进度、制定项目进度计划,如何利用挣值法跟踪项目进度,项目经理的职责与必备素质、应具备的能力、工作方法,如何根据各种组织结构及其优缺点进行选择,如何对于风险进行定性定量分析等等,通过这次培训有了初步的掌握,将能够很快地应用到实际工作中。

    问题点评:在软件企业中,以前几乎没有专门招收项目管理专业的人员来担任项目经理(甚至很少是管理专业的),被任命的项目经理主要是因为他们能够在技术上独当一面,而管理方面特别是项目管理方面的知识比较缺乏。因此项目经理接受系统的项目管理知识培训是非常必要的,有了专业领域的知识与实践,再加上项目管理知识与实践和一般管理的知识和经验的有机结合,必能大大提高项目经理的项目管理水平。

    解决方案:实行项目经理知识技能资格考核制度,让项目经理自觉补充学习项目管理的知识和一些常用工具和方法。

    问题二:项目计划意识问题

    相关对象:项目经理

    问题说明:项目经理对总体计划、阶段计划的作用认识不足。项目经理认为计划不如变化快,项目中也有很多不确定的因素,做计划是走过场,因此制定总体计划时比较随意,不少事情没有仔细考虑;阶段计划因工作忙等理由经常拖延,造成计划与控制管理脱节,无法进行有效的进度控制管理。

    问题点评:渐近明细是项目的特点,但这并不意味着不需要计划。没有计划或者是随意的不负责任的计划的项目是一种无法控制的项目。在高技术行业,日新月异是主要特点,因此计划的制定需要在一定条件的限制和假设之下采用渐近明细的方式进行不断完善。例如对于较为大型的软件开发项目的工作分解结构WBS可采用二次WBS方法。即根据总体阶段划分的总体WBS和专门针对详细设计或编码阶段的二次WBS。这其中部分的原因是需求的颗粒度在一开始往往是比较粗的,因此根据功能点对于整体项目规模的估计误差范围也是比较大的。更为重要的原因是,需求往往不是编码工作分解的准确依据,因为一个需求的功能点可能对应多个代码模块,而多个需求的功能点也可能只对应一个或少数代码模块,同时还有软件复用等因素要考虑,因此只有在概要设计完成以后才能准确地得到详细设计或编码阶段的二次WBS,根据代码模块的合理划分而得出的二次WBS才能在详细设计、编码阶段乃至测试阶段起到有效把握和控制进度的作用。有些项目的需求或设计做得不够详细,无法对工作任务的分解、均衡分配和进度管理起参考作用,对此应当及时改善。

    制定计划的过程就是一个对项目逐渐了解掌握的过程,通过认真地制定计划,项目经理可以知道哪些要素是明确的,哪些要素是要逐渐明确的,通过渐近明细不断完善项目计划。阶段计划中包含的工作汇报和下一阶段工作安排是掌握项目进度的依据,从阶段计划对照总体计划,才能一目了然地看出工作的进展情况。制定计划的过程,也是在进度、资源、范围之间寻求一种平衡的过程。制定计划的精髓不在于写出一份好看的文档,而在于运用您的智慧去应对各种问题和面临风险并尽可能做出前瞻性的思考。一旦计划被负责任地完成,他就可以给自己一个和管理层或客户交流与协商的基础,帮助你在项目过程中防范各种问题的出现,帮助你保证项目按时完成。

    解决方案:提高项目经理的计划意识,采用项目计划制定相关各种知识、技术、工具,加强对开发计划、阶段计划的有效性进行事前事后的评估。

    问题三、管理意识问题

    相关对象:项目经理

    问题说明:部分项目经理没有意识到自己项目经理的角色,从总体上去把握管理整个项目,而是埋头于具体的技术工作,造成项目组成员之间忙的忙、闲的闲,计划不周、任务不均、资源浪费。

    问题点评:在软件企业中,项目经理大多是技术骨干,技术方面的知识比较深厚,但无论是项目管理知识,还是项目管理必备的技能、项目管理必备的素质都有待补充和提高,项目管理经验也有待丰富。有些项目经理对于一些不服管理的技术人员,没有较好的管理方法,工作不好安排的工作只好自己做。另外由于工作分解结构设计的合理性,项目任务无法有效、合理地分配给相关成员,以达到“负载均衡”。因此技术骨干在担任项目经理之前,最好能经过系统的项目管理知识,特别是其中的人力资源管理、沟通管理的学习,并且在实际工作中不断提高自己的管理素质,丰富项目管理经验,提高项目管理意识。

    解决方案:加强项目管理方面的培训,并通过对考核指标的合理设定和宣传引导项目经理更好地做好项目管理工作。

    问题四:沟通意识问题

    相关人员:项目经理、项目组成员

    问题说明:在项目中一些重要信息没有进行充分和有效的沟通。在制定计划、意见反馈、情况通报、技术问题或成果等方面与相关人员的沟通不足,造成各做各事、重复劳动,甚至造成不必要的损失;有些人没有每天定时收邮件的习惯,以至于无法及时接收最新的信息。

    问题点评:项目沟通管理指出:“管理者要用70%的时间用于与人沟通,而项目经理需要花费90%或更多的时间来沟通”。和问题三的情况类似,在软件企业中,项目经理大多是技术骨干,而项目组成员也都是“高科技人员”,都具有“从专业或学术出发、工作自主性大、自我欣赏、以自我为中心”等共同的特点。因此妨碍沟通的因素主要是“感觉和态度问题”,也就是沟通意识和习惯的问题。在系统的实施阶段或软件开发的试运行阶段,项目成员基本上是持续是在客户方进行工作,这种情况非常容易忽视沟通。项目组与组织之间、项目组与项目组成员之间,甚至同一个项目组的不同成员之间,都有可能在不同的地点,如果没有足够的沟通意识和沟通制度、沟通工具,就有可能造成信息不畅,从而加大项目失败的风险。即使都在公司内部也应做到及时沟通。所以项目经理不但自己要把工作重点放在沟通,善于沟通,还要引导、约定整个项目团队进行及时充分的沟通。

    解决方案:制定有效的沟通制度和沟通机制,对由于缺乏沟通而造成的事件进行通报作为教训提醒,以提高沟通意识;沟通方式应根据内容而多样化,讲究有效率的沟通;通过制度规定对由于未及时收取邮件而造成损失的责任归属;对于特别重要的内容要采用多种方式进行有效沟通以确保传达到位,例如除发送邮件外还要电话提醒、回执等,重要的内容还要通过举行各种会议进行传达。

    问题五:风险管理意识问题

    相关人员:项目经理

    问题说明:项目经理没有充分分析可能的风险,对付风险的策略考虑比较简单。项目经理在做项目规划时常常没有做专门的风险管理计划文档,而是合并在项目计划书中。有些项目经理没有充分意识到风险管理的重要性,对计划书中风险管理的章节简单应付了事,随便列出几个风险,随便地写一些简单的对策,对于后面的风险防范起不到什么指导作用。

    问题点评:项目风险管理是对项目潜在的意外损失进行规划、识别、估计、评价、应对和监控的过程,是对项目目标的主动控制手段。采取主动行动,创造条件,尽量扩大风险的有利结果,以最少的成本保证安全、可靠地实现项目目标。因此项目风险管理对于保证项目目标的实现是非常重要的。

    解决方案:通过学习项目管理知识掌握风险识别、量化、对策研究、反应控制的工具和方法掌握项目风险管理所必备的知识。通过加强对项目规划中风险管理计划的审核提高项目组的风险管理意识。总结本行业项目中常见的风险及其对策作为风险管理计划中必要的风险内容,并切实评估相应对策的有效性和可行性。
    ]]>
    CVS使用手册详本 http://www.phpv.net/html/235.html http://www.phpv.net/html/235.html#comment Sat, 03 Jul 2004 01:12:37 +0000 admin http://www.phpv.net/html/235.html 内容摘要:

    CVS是一个C/S系统,多个开发人员通过一个中心版本控制系统来记录文件版本,从而达到保证文件同步的目的。工作模式如下:

           CVS服务器(文件版本库)
    / |
    (版 本 同 步)
    / |
    开发者1 开发者2 开发者3

    作为一般开发人员挑选2,6看就可以了,CVS的管理员则更需要懂的更多一些,最后还简单介绍了一些Windows下的cvs客户端使用,CVS远程用户认证的选择及与BUG跟踪系统等开发环境的集成问题。

    1. CVS环境初始化:CVS环境的搭建 管理员
    2. CVS的日常使用:日常开发中最常用的CVS命令, 开发人员 管理员
    3. CVS的分支开发:项目按照不同进度和目标并发进行 管理员
    4. CVS的用户认证:通过SSH的远程用户认证,安全,简单 管理员
    5. CVSWEB:CVS的WEB访问界面大大提高代码版本比较的效率 管理员
    6. CVS TAG:将$Id$ 加入代码注释中,方便开发过程的跟踪开发人员
    7. CVS vs VSS: CVS和Virsual SourceSafe的比较 开发人员 管理员
    8. WinCVS: 通过SSH认证的WinCVS认证设置
    9. 基于CVSTrac的小组开发环境搭建:通过CVSTrac实现web界面的CVS用户管理,集成的BUG跟踪和WIKI交流
    10. CVS中的用户权限管理:基于系统用户的CVS权限管理和基于CVSROOT/passwd的虚拟用户管理

    一个系统20%的功能往往能够满足80%的需求,CVS也不例外,以下是CVS最常用的功能,可能还不到它全部命令选项的20%,作为一般开发人员平时会用cvs update和cvs commit就够了,更多的需求在实际应用过程中自然会出现,不时回头看看相关文档经常有意外的收获。


    CVS环境初始化

    环境设置:指定CVS库的路径CVSROOT

    tcsh
    setenv CVSROOT /path/to/cvsroot
    bash
    CVSROOT=/path/to/cvsroot ; export CVSROOT

    后面还提到远程CVS服务器的设置:
    CVSROOT=:ext:$USER@test.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH

    初始化:CVS版本库的初始化。
    cvs init

    一个项目的首次导入
    cvs import -m "write some comments here" project_name vendor_tag release_tag
    执行后:会将所有源文件及目录导入到/path/to/cvsroot/project_name目录下
    vender_tag: 开发商标记
    release_tag: 版本发布标记

    项目导出:将代码从CVS库里导出
    cvs checkout project_name
    cvs 将创建project_name目录,并将最新版本的源代码导出到相应目录中。这个checkout和Virvual SourceSafe中的check out不是一个概念,相对于Virvual SourceSafe的check out是cvs update, check in是cvs commit。

    CVS的日常使用

    注意:第一次导出以后,就不是通过cvs checkout来同步文件了,而是要进入刚才cvs checkout project_name导出的project_name目录下进行具体文件的版本同步(添加,修改,删除)操作。

    将文件同步到最新的版本
    cvs update
    不制定文件名,cvs将同步所有子目录下的文件,也可以制定某个文件名/目录进行同步
    cvs update file_name
    最好每天开始工作前或将自己的工作导入到CVS库里前都要做一次,并养成“先同步 后修改”的习惯,和Virvual SourceSafe不同,CVS里没有文件锁定的概念,所有的冲突是在commit之前解决,如果你修改过程中,有其他人修改并commit到了CVS 库中,CVS会通知你文件冲突,并自动将冲突部分用
    >>>>>>
    content on cvs server
    <<<<<<
    content in your file
    >>>>>>
    标记出来,由你确认冲突内容的取舍。
    版本冲突一般是在多个人修改一个文件造成的,但这种项目管理上的问题不应该指望由CVS来解决。

    确认修改写入到CVS库里
    cvs commit -m "write some comments here" file_name

    注意:CVS的很多动作都是通过cvs commit进行最后确认并修改的,最好每次只修改一个文件。在确认的前,还需要用户填写修改注释,以帮助其他开发人员了解修改的原因。如果不用写-m "comments"而直接确认`cvs commit file_name` 的话,cvs会自动调用系统缺省的文字编辑器(一般是vi)要求你写入注释。
    注释的质量很重要:所以不仅必须要写,而且必须写一些比较有意义的内容:以方便其他开发人员能够很好的理解
    不好的注释,很难让其他的开发人员快速的理解:比如: -m "bug fixed" 甚至 -m ""
    好的注释,甚至可以用中文: -m "在用户注册过程中加入了Email地址校验"


    修改某个版本注释:每次只确认一个文件到CVS库里是一个很好的习惯,但难免有时候忘了指定文件名,把多个文件以同样注释commit到CVS库里了,以下命令可以允许你修改某个文件某个版本的注释:
    cvs admin -m 1.3:"write some comments here" file_name

    添加文件
    创建好新文件后,比如:touch new_file
    cvs add new_file
    注意:对于图片,Word文档等非纯文本的项目,需要使用cvs add -kb选项按2进制文件方式导入(k表示扩展选项,b表示binary),否则有可能出现文件被破坏的情况
    比如:
    cvs add -kb new_file.gif
    cvs add -kb readme.doc

    如果关键词替换属性在首次导入时设置错了怎么办?
    cvs admin -kkv new_file.css

    然后确认修改并注释
    cvs ci -m "write some comments here"

    删除文件
    将某个源文件物理删除后,比如:rm file_name
    cvs rm file_name
    然后确认修改并注释
    cvs ci -m "write some comments here"
    以上面前2步合并的方法为:
    cvs rm -f file_name
    cvs ci -m "why delete file"
    注意:很多cvs命令都有缩写形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;

    添加目录
    cvs add dir_name

    查看修改历史
    cvs log file_name
    cvs history file_name

    查看当前文件不同版本的区别
    cvs diff -r1.3 -r1.5 file_name
    查看当前文件(可能已经修改了)和库中相应文件的区别
    cvs diff file_name
    cvs的web界面提供了更方便的定位文件修改和比较版本区别的方法,具体安装设置请看后面的cvsweb使用

    正确的通过CVS恢复旧版本的方法
    如果用cvs update -r1.2 file.name
    这个命令是给file.name加一个STICK TAG: "1.2" ,虽然你的本意只是想将它恢复到1.2版本
    正确的恢复版本的方法是:cvs update -p -r1.2 file_name >file_name
    如果不小心已经加成STICK TAG的话:用cvs update -A 解决

    移动文件/文件重命名
    cvs里没有cvs move或cvs rename,因为这两个操作是可以由先cvs remove old_file_name,然后cvs add new_file_name实现的。

    删除/移动目录
    最方便的方法是让管理员直接移动,删除CVSROOT里相应目录(因为CVS一个项目下的子目录都是独立的,移动到$CVSROOT目录下都可以作为新的独立项目:好比一颗树,其实砍下任意一枝都能独立存活),对目录进行了修改后,要求其开发人员重新导出项目cvs checkout project_name 或者用cvs update -dP同步。

    项目发布导出不带CVS目录的源文件
    做开发的时候你可能注意到了,每个开发目录下,CVS都创建了一个CVS/目录。里面有文件用于记录当前目录和CVS库之间的对应信息。但项目发布的时候你一般不希望把文件目录还带着含有CVS信息的CVS目录吧,这个一次性的导出过程使用cvs export命令,不过export只能针对一个TAG或者日期导出,比如:
    cvs export -r release1 project_name
    cvs export -D 20021023 project_name
    cvs export -D now project_name

    CVS Branch:项目多分支同步开发

    确认版本里程碑:多个文件各自版本号不一样,项目到一定阶段,可以给所有文件统一指定一个阶段里程碑版本号,方便以后按照这个阶段里程碑版本号导出项目,同时也是项目的多个分支开发的基础。

    cvs tag release_1_0

    开始一个新的里程碑
    cvs commit -r 2 标记所有文件开始进入2.x的开发

    注意:CVS里的revsion和软件包的发布版本可以没有直接的关系。但所有文件使用和发布版本一致的版本号比较有助于维护。

    版本分支的建立
    在开发项目的2.x版本的时候发现1.x有问题,但2.x又不敢用,则从先前标记的里程碑:release_1_0导出一个分支 release_1_0_patch
    cvs rtag -b -r release_1_0 release_1_0_patch proj_dir

    一些人先在另外一个目录下导出release_1_0_patch这个分支:解决1.0中的紧急问题,
    cvs checkout -r release_1_0_patch
    而其他人员仍旧在项目的主干分支2.x上开发

    在release_1_0_patch上修正错误后,标记一个1.0的错误修正版本号
    cvs tag release_1_0_patch_1

    如果2.0认为这些错误修改在2.0里也需要,也可以在2.0的开发目录下合并release_1_0_patch_1中的修改到当前代码中:
    cvs update -j release_1_0_patch_1

    CVS的远程认证通过SSH远程访问CVS

    使用cvs本身基于pserver的远程认证很麻烦,需要定义服务器和用户组,用户名,设置密码等,

    常见的登陆格式如下:
    cvs -d :pserver:cvs_user_name@cvs.server.address:/path/to/cvsroot login
    例子:
    cvs -d :pserver:cvs@samba.org:/cvsroot login

    不是很安全,因此一般是作为匿名只读CVS访问的方式。从安全考虑,通过系统本地帐号认证并通过SSH传输是比较好的办法,通过在客户机的 /etc/profile里设置一下内容:
    CVSROOT=:ext:$USER@cvs.server.address#port:/path/to/cvsroot CVS_RSH=ssh; export CVSROOT CVS_RSH
    所有客户机所有本地用户都可以映射到CVS服务器相应同名帐号了。

    比如:

    CVS服务器是192.168.0.3,上面CVSROOT路径是/home/cvsroot,另外一台开发客户机是192.168.0.4,如果 tom在2台机器上都有同名的帐号,那么从192.168.0.4上设置了:
    export CVSROOT=:ext:tom@192.168.0.3:/home/cvsroot
    export CVS_RSH=ssh
    tom就可以直接在192.168.0.4上对192.168.0.3的cvsroot进行访问了(如果有权限的话)
    cvs checkout project_name
    cd project_name
    cvs update
    ...
    cvs commit

    如果CVS所在服务器的SSH端口不在缺省的22,或者和客户端与CVS服务器端SSH缺省端口不一致,有时候设置了:
    :ext:$USER@test.server.address#port:/path/to/cvsroot

    仍然不行,比如有以下错误信息:
    ssh: test.server.address#port: Name or service not known
    cvs [checkout aborted]: end of file from server (consult above messages if any)

    解决的方法是做一个脚本指定端口转向(不能使用alias,会出找不到文件错误):
    创建一个/usr/bin/ssh_cvs文件,假设远程服务器的SSH端口是非缺省端口:34567
    #!/bin/sh
    /usr/bin/ssh -p 34567 "$@"
    然后:chmod +x /usr/bin/ssh_cvs
    并CVS_RSH=ssh_cvs; export CVS_RSH

    注意:port是指相应服务器SSH的端口,不是指cvs专用的pserver的端口

    CVSWEB:提高文件浏览效率

    CVSWEB就是CVS的WEB界面,可以大大提高程序员定位修改的效率:

    使用的样例可以看:http://www.freebsd.org/cgi/cvsweb.cgi

    CVSWEB的下载:CVSWEB从最初的版本已经演化出很多功能界面更丰富的版本,这个是我个人感觉安装设置比较方便的:
    原先在:http://www.spaghetti-code.de/software/linux/cvsweb/,但目前已经删除,目前仍可以在本站下载CVSWEB,其实最近2年FreeBSD的CVSWeb项目已经有了更好的发展吧,而当初没有用FreeBSD那个版本主要就是因为没有彩色的文件Diff功能。
    下载解包:
    tar zxf cvsweb.tgz
    把配置文件cvsweb.conf放到安全的地方(比如和apache的配置放在同一个目录下),
    修改:cvsweb.cgi让CGI找到配置文件:
    $config = $ENV{'CVSWEB_CONFIG'} || '/path/to/apache/conf/cvsweb.conf';

    转到/path/to/apache/conf下并修改cvsweb.conf:

    1. 修改CVSROOT路径设置:
      %CVSROOT = (
      'Development' => '/path/to/cvsroot', #<==修改指向本地的CVSROOT
      );
    2. 缺省不显示已经删除的文档:
      "hideattic" => "1",#<==缺省不显示已经删除的文档
    3. 在配置文件cvsweb.conf中还可以定制页头的描述信息,你可以修改$long_intro成你需要的文字

    CVSWEB可不能随便开放给所有用户,因此需要使用WEB用户认证:
    先生成 passwd:
    /path/to/apache/bin/htpasswd -c cvsweb.passwd user

    修改httpd.conf: 增加
    <Directory "/path/to/apache/cgi-bin/cvsweb/">
    AuthName "CVS Authorization"
    AuthType Basic
    AuthUserFile /path/to/cvsweb.passwd
    require valid-user
    </Directory>

    CVS TAGS: $Id: cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $

    将$Id: cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $ 加在程序文件开头的注释里是一个很好的习惯,cvs能够自动解释更新其中的内容成:file_name version time user_name 的格式,比如:cvs_card.txt,v 1.1 2002/04/05 04:24:12 chedong Exp,可以这些信息了解文件的最后修改人和修改时间


    几个常用的缺省文件:
    default.php
    <?php
    /*
    * Copyright (c) 2002 Company Name.
    * $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $
    */

    ?>
    ====================================
    Default.java: 注意文件头一般注释用 /* 开始 JAVADOC注释用 /** 开始的区别
    /*
    * Copyright (c) 2002 MyCompany Name.
    * $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $
    */

    package com.mycompany;

    import java.;

    /**
    * comments here
    */
    public class Default {
    /**
    * Comments here
    * @param
    * @return
    */
    public toString() {

    }
    }
    ====================================
    default.pl:
    #!/usr/bin/perl -w
    # Copyright (c) 2002 Company Name.
    # $Header: /home/cvsroot/tech/cvs_card.html,v 1.9 2003/11/09 07:57:11 chedong Exp $

    # file comments here

    use strict;

    CVS vs VSS

    CVS没有文件锁定模式,VSS在check out同时,同时记录了文件被导出者锁定。

    CVS的update和commit, VSS是get_lastest_version和check in

    对应VSS的check out/undo check out的CVS里是edit和unedit

    在CVS中,标记自动更新功能缺省是打开的,这样也带来一个潜在的问题,就是不用-kb方式添加binary文件的话在cvs自动更新时可能会导致文件失效。

    $Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $ $Date: 2003/11/09 07:57:11 $这样的标记在Virsual SourceSafe中称之为Keyword Explaination,缺省是关闭的,需要通过OPITION打开,并指定需要进行源文件关键词扫描的文件类型:*.txt,*.java, *.html...

    对于Virsual SourceSafe和CVS都通用的TAG有:
    $Header: /home/cvsroot/tech/cvs_card.html,v 1.5 2003/03/09 08:41:46 chedong Exp $
    $Author: chedong $
    $Date: 2003/11/09 07:57:11 $
    $Revision: 1.9 $

    我建议尽量使用通用的关键词保证代码在CVS和VSS都能方便的跟踪。

    WinCVS

    下载:

    cvs Windows客户端:目前稳定版本为1.2
    http://cvsgui.sourceforge.net
    ssh Windows客户端
    http://www.networksimplicity.com/openssh/

    安装好以上2个软件以后:
    WinCVS客户端的admin==>preference设置
    1 在general选单里
    设置CVSROOT: username@192.168.0.123:/home/cvsroot
    设置Authorization: 选择SSH server

    2 Port选单里
    钩上:check for alternate rsh name
    并设置ssh.exe的路径,缺省是装在 C:Program FilesNetworkSimplicitysshssh.exe

    然后就可以使用WinCVS进行cvs操作了,所有操作都会跳出命令行窗口要求你输入服务器端的认证密码。

    当然,如果你觉得这样很烦的话,还有一个办法就是生成一个没有密码的公钥/私钥对,并设置CVS使用基于公钥/私钥的SSH认证(在general 选单里)。

    可以选择的diff工具:examdiff
    下载:
    http://www.prestosoft.com/examdiff/examdiff.htm
    还是在WinCVS菜单admin==>preference的WinCVS选单里
    选上:Externel diff program
    并设置diff工具的路径,比如:C:Program Filesed16iExamDiff.exe
    在对文件进行版本diff时,第一次需要将窗口右下角的use externel diff选上。

    基于CVSTrac的小组开发环境搭建

    作为一个小组级的开发环境,版本控制系统和BUG跟踪系统等都涉及到用户认证部分。如何方便的将这些系统集成起来是一个非常困难的事情,毕竟我们不能指望 Linux下有像Source Offsite那样集成度很高的版本控制/BUG跟踪集成系统。

    我个人是很反对使用pserver模式的远程用户认证的,但如果大部分组员使用WINDOWS客户端进行开发的话,总体来说使用 CVSROOT/passwd认证还是很难避免的,但CVS本身用户的管理比较麻烦。本来我打算自己用perl写一个管理界面的,直到我发现了 CVSTrac:一个基于WEB界面的BUG跟踪系统,它外挂在CVS系统上的BUG跟踪系统,其中就包括了WEB界面的CVSROOT/passwd文件的管理,甚至还集成了WIKIWIKI讨论组功能。

    这里首先说一下CVS的pserver模式下的用户认证,CVS的用户认证服务是基于inetd中的:
    cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver
    一般在2401端口(这个端口号很好记:49的平方)

    CVS用户数据库是基于CVSROOT/passwd文件,文件格式:
    [username]:[crypt_password]:[mapping_system_user]
    由于密码都用的是UNIX标准的CRYPT加密,这个passwd文件的格式基本上是apache的htpasswd格式的扩展(比APACHE的 PASSWD文件多一个系统用户映射字段),所以这个文件最简单的方法可以用
    apache/bin/htpasswd -b myname mypassword
    创建。注意:通过htpasswd创建出来的文件会没有映射系统用户的字段
    例如:
    new:geBvosup/zKl2
    setup:aISQuNAAoY3qw
    test:hwEpz/BX.rEDU

    映射系统用户的目的在于:你可以创建一个专门的CVS服务帐号,比如用apache的运行用户apache,并将/home/cvsroot目录下的所有权限赋予这个用户,然后在passwd文件里创建不同的开发用户帐号,但开发用户帐号最后的文件读写权限都映射为apache用户,在SSH模式下多个系统开发用户需要在同一个组中才可以相互读写CVS库中的文件。

    进一步的,你可以将用户分别映射到apache这个系统用户上。
    new:geBvosup/zKl2:apache
    setup:aISQuNAAoY3qw:apache
    test:hwEpz/BX.rEDU:apache

    CVSTrac很好的解决了CVSROOT/passwd的管理问题,而且包含了BUG跟踪报告系统和集成WIKIWIKI交流功能等,使用的 CGI方式的安装,并且基于GNU Public License

    在inetd里加入cvspserver服务:
    cvspserver stream tcp nowait apache /usr/bin/cvs cvs --allow-root=/home/cvsroot pserver

    xietd的配置文件:%cat cvspserver
    service cvspserver
    {
    disable = no
    socket_type = stream
    wait = no
    user = apache
    server = /usr/bin/cvs
    server_args = -f --allow-root=/home/cvsroot pserver
    log_on_failure += USERID
    }

    注意:这里的用户设置成apache目的是和/home/cvsroot的所有用户一致,并且必须让这个这个用户对/home/cvsroot/下的 CVSROOT/passwd和cvstrac初始化生成的myproj.db有读取权限。

    安装过程

    1. 下载:可以从http://www.cvstrac.org 下载
      我用的是已经在Linux上编译好的应用程序包:cvstrac-1.1.2.bin.gz,
      %gzip -d cvstrac-1.1.2.bin.gz
      %chmod +x cvstrac-1.1.2.bin
      #mv cvstarc-1.1.1.bin /usr/bin/cvstrac
      如果是从源代码编译:
      从 http://www.sqlite.org/download.html 下载SQLITE的rpm包:
      rpm -i sqlite-devel-2.8.6-1.i386.rpm
      从 ftp://ftp.cvstrac.org/cvstrac/ 下载软件包
      解包,假设解包到/home/chedong/cvstrac-1.1.2下,并规划将cvstrac安装到/usr/local/bin目录下, cd /home/chedong/cvstrac-1.1.2 编辑linux-gcc.mk:
      修改:
      SRCDIR = /home/chedong/cvstrac-1.1.2
      INSTALLDIR = /usr/local/bin
      然后
      mv linux-gcc.mk Makefile
      make
      #make install

    2. 初始化cvstrac数据库:假设数据库名是 myproj
      在已经装好的CVS服务器上(CVS库这时候应该已经是初始化好了,比如:cvs init初始化在/home/cvsroot里),运行一下
      %cvstrac init /home/cvsroot myproj
      运行后,/home/cvsroot里会有一个的myproj.db库,使用CVSTRAC服务,/home/cvsroot/myproj.db /home/cvsroot/CVSROOT/readers /home/cvsroot/CVSROOT/writers /home/cvsroot/CVSROOT/passwd这几个文件对于web服务的运行用户应该是可写的,在RedHat8上,缺省就有一个叫 apache用户和一个apache组,所以在httpd.conf文件中设置了用apache用户运行web服务:
      User apache
      Group apache,
      然后设置属于apache用户和apache组
      #chown -R apache:apache /home/cvsroot
      -rw-r--r-- 1 apache apache 55296 Jan 5 19:40 myproj.db
      drwxrwxr-x 3 apache apache 4096 Oct 24 13:04 CVSROOT/
      drwxrwxr-x 2 apache apache 4096 Aug 30 19:47 some_proj/
      此外还在/home/cvsroot/CVSROOT中设置了:
      chmod 664 readers writers passwd
    3. 在apche/cgi-bin目录中创建脚本cvstrac:
      #!/bin/sh
      /usr/bin/cvstrac cgi /home/cvsroot
      设置脚本可执行:
      chmod +x /home/apache/cgi-bin/cvstrac
    4. 从 http://cvs.server.address/cgi-bin/cvstrac/myproj 进入管理界面
      缺省登录名:setup 密码 setup
      对于一般用户可以从:
      http://cvs.server.address/cgi-bin/cvstrac/myproj
    5. 在setup中重新设置了CVSROOT的路径后,/home/cvsroot
      如果是初次使用需要在/home/cvsroot/CVSROOT下创建passwd, readers, writers文件
      touch passwd readers writers
      然后设置属于apache用户,
      chown apache.apache passwd readers writers
      这样使用setup用户创建新用户后会同步更新CVSROOT/passwd下的帐号

    修改登录密码,进行BUG报告等,
    更多使用细节可以在使用中慢慢了解。

    对于前面提到的WinCVS在perference里设置:
    CVSROOT栏输入:username@ip.address.of.cvs:/home/cvsroot
    Authenitication选择:use passwd file on server side
    就可以了从服务器上进行CVS操作了。

    CVS的用户权限管理

    CVS的权限管理分2种策略:

    • 基于系统文件权限的系统用户管理:适合多个在Linux上使用系统帐号的开发人员进行开发。
    • 基于CVSROOT/passwd的虚拟用户管理:适合多个在Windows平台上的开发人员将帐号映射成系统帐号使用。
    为什么使用apache/apache用户?首先RedHat8中缺省就有了,而且使用这个用户可以方便通过cvstrac进行WEB管理。
    chown -R apache.apache /home/cvsroot
    chmod 775 /home/cvsroot

    Linux上通过ssh连接CVS服务器的多个开发人员:通过都属于apache组实现文件的共享读写
    开发人员有开发服务器上的系统帐号:sysuser1 sysuser2,设置让他们都属于apache组,因为通过cvs新导入的项目都是对组开放的:664权限的,这样无论那个系统用户导入的项目文件,只要文件的组宿主是apache,所有其他同组系统开发用户就都可以读写;基于ssh远程认证的也是一样。

       apache(system group)
    /            |          
    sysuser1   sysuser2     sysuser3

    Windows上通过cvspserver连接CVS服务器的多个开发人员:通过在passwd文件种映射成 apache用户实现文件的共享读写
    他们的帐号通过CVSROOT/passwd和readers writers这几个文件管理;通过cvstrac设置所有虚拟用户都映射到apache用户上即可。

       apache(system user)
    /            |            
    windev1     windev2      windev3             

    利用cvs + (WinCVS/cvsweb/cvstrac),构成了一个相对完善的跨平台工作组开发版本控制环境。

    相关资源:

    CVS HOME:
    http://www.cvshome.org

    CVS FAQ:
    http://www.loria.fr/~molli/cvs-index.html

    相关网站:
    http://directory.google.com/Top/Computers/Software/Configuration_Management/Tools/Concurrent_Versions_System/

    CVS--并行版本系统
    http://www.soforge.com/cvsdoc/zh_CN/book1.html

    CVS 免费书:
    http://cvsbook.red-bean.com/

    CVS 命令的速查卡片:
    http://www.refcards.com/about/cvs.html

    WinCVS:
    http://cvsgui.sourceforge.net/

    CVSTrac: A Web-Based Bug And Patch-Set Tracking System For CVS
    http://www.cvstrac.org

    StatCVS:基于CVS的代码统计工具:按代码量,按开发者的统计表等
    http://sourceforge.net/projects/statcvs

    如何在WEB开发中规划CVS上:在Google上查 "cvs web development"
    http://ccm.redhat.com/bboard-archive/cvs_for_web_development/index.html

    一些集成了CVS的IDE环境:
    Eclipse
    Magic C++ ]]>