优秀程序员值得借鉴的一些信息

目录

  <1>:关于项目开发:项目的75个注意事项

  <2>:关于程序员:程序员从初级到中级10个秘诀

  <3>:关于软件设计:一些软件设计的原则

  <4>:关于工作:每天写出好代码的5个建议

  <5>:关于工作环境:程序员的工作效率和工作环境

 

<1>:关于项目开发:

项目的75个注意事项

​1. 你们的项目组使用源代码管理工具了么? 

应该用。VSS、CVS、PVCS、ClearCase、CCC/Harvest、FireFly都可以。我的选择是VSS。 

 

2. 你们的项目组使用缺陷管理系统了么? 

应该用。ClearQuest太复杂,我的推荐是BugZilla。 

 

3. 你们的测试组还在用Word写测试用例么? 

不要用Word写测试用例(Test Case)。应该用一个专门的系统,可以是Test Manager,也可以是自己开发一个ASP.NET的小网站。主要目的是Track和Browse。 

 

4. 你们的项目组有没有建立一个门户网站? 

要 有一个门户网站,用来放Contact Info、Baselined Schedule、News等等。推荐 Sharepoint Portal Server 2003来实现,15分钟就搞定。买不起SPS 2003可以用 WSS (Windows Sharepoint Service)。 

 

5. 你们的项目组用了你能买到最好的工具么? 

应该用尽量好的工具来工作。比如,应该用VS.NET而不是Notepad来写C#。用Notepad写程序多半只是一种炫耀。但也要考虑到经费,所以说是“你能买到最好的”。 

 

6. 你们的程序员工作在安静的环境里么? 

需要安静环境。这点极端重要,而且要保证每个人的空间大于一定面积。 

 

7. 你们的员工每个人都有一部电话么? 

需要每人一部电话。而且电话最好是带留言功能的。当然,上这么一套带留言电话系统开销不小。不过至少每人一部电话要有,千万别搞得经常有人站起来喊:“某某某电话”。《人件》里面就强烈谴责这种做法。 

 

8. 你们每个人都知道出了问题应该找谁么? 

应该知道。任何一个Feature至少都应该有一个Owner,当然,Owner可以继续Dispatch给其他人。 

 

9. 你遇到过有人说“我以为…”么? 

要消灭“我以为”。Never assume anything。 

 

10. 你们的项目组中所有的人都坐在一起么? 

需要。我反对Virtual Team,也反对Dev在美国、Test在中国这种开发方式。能坐在一起就最好坐在一起,好处多得不得了。 

 

11. 你们的进度表是否反映最新开发进展情况? 

应该反映。但是,应该用Baseline的方法来管理进度表:维护一份稳定的Schedule,再维护一份最新更改。Baseline的方法也应该用于其它的Spec。Baseline是变更管理里面的一个重要手段。 

 

12. 你们的工作量是先由每个人自己估算的么? 

应该让每个人自己估算。要从下而上估算工作量,而不是从上往下分派。除非有其他原因,比如政治任务工期固定等。 

 

13. 你们的开发人员从项目一开始就加班么? 

不要这样。不要一开始就搞疲劳战。从项目一开始就加班,只能说明项目进度不合理。当然,一些对日软件外包必须天天加班,那属于剥削的范畴。 

 

14. 你们的项目计划中Buffer Time是加在每个小任务后面的么? 

不要。Buffer Time加在每个小任务后面,很容易轻易的就被消耗掉。Buffer Time要整段的加在一个Milestone或者checkpoint前面。 

 

15. 值得再多花一些时间,从95%做到100%好 

值得,非常值得。尤其当项目后期人困马乏的时候,要坚持。这会给产品带来质的区别。 

 

16. 登记新缺陷时,是否写清了重现步骤? 

要。这属于Dev和Test之间的沟通手段。面对面沟通需要,详细填写Repro Steps也需要。 

 

17. 写新代码前会把已知缺陷解决么? 

要。每个人的缺陷不能超过10个或15个,否则必须先解决老的bug才能继续写新代码。 

 

18. 你们对缺陷的轻重缓急有事先的约定么? 

必须有定义。Severity要分1、2、3,约定好:蓝屏和Data Lost算Sev 1,Function Error算Sev 2,界面上的算Sev 3。但这种约定可以根据产品质量现状适当进行调整。 

 

19. 你们对意见不一的缺陷有三国会议么? 

必须要有。要有一个明确的决策过程。这类似于CCB (Change Control Board)的概念。 

 

20. 所有的缺陷都是由登记的人最后关闭的么? 

Bug应该由Opener关闭。Dev不能私自关闭Bug。 

 

21. 你们的程序员厌恶修改老的代码么? 

厌恶是正常的。解决方法是组织Code Review,单独留出时间来。XP也是一个方法。 

 

22. 你们项目组有Team Morale Activity么? 

每个月都要搞一次,唱歌,Outing,打球、开卡丁车等等,一定要有。不要剩这些钱。 

 

23. 你们项目组有自己的Logo么? 

要有自己的Logo。至少应该有自己的Codename。 

 

24. 你们的员工有印有公司Logo的T-Shirt么? 

要有。能增强归属感。当然,T-Shirt要做的好看一些,最好用80支的棉来做。别没穿几次就破破烂烂的。 

 

25. 总经理至少每月参加次项目组会议 

要的。要让team member觉得高层关注这个项目。 

 

26. 你们是给每个Dev开一个分支么? 

反对。Branch的管理以及Merge的工作量太大,而且容易出错。 

 

27. 有人长期不Check-In代码么? 

不可以。对大部分项目来说,最多两三天就应该Check-In。 

 

28. 在Check-In代码时都填写注释了么? 

要写的,至少一两句话,比如“解决了Bug No.225”。如果往高处拔,这也算做“配置审计”的一部分。 

 

29. 有没有设定每天Check-In的最后期限? 

要的,要明确Check-In Deadline。否则会Build Break。 

 

30. 你们能把所有源码一下子编译成安装文件吗? 

要的。这是每日编译(Daily Build)的基础。而且必须要能够做成自动的。 

 

31. 你们的项目组做每日编译么? 

当然要做。有三样东西是软件项目/产品开发必备的:1. bug management; 2. source control; 3. daily build。 

 

32. 你们公司有没有积累一个项目风险列表? 

要。Risk Inventory。否则,下个项目开始的时候,又只能拍脑袋分析Risk了。 

 

33. 设计越简单越好 

越简单越好。设计时候多一句话,将来可能就带来无穷无尽的烦恼。应该从一开始就勇敢的砍。这叫scope management。 

 

34. 尽量利用现有的产品、技术、代码 

千 万别什么东西都自己Coding。BizTalk和Sharepoint就是最好的例子,有这两个作为基础,可以把起点提高很多。或者可以尽量多用现成的 Control之类的。或者尽量用XML,而不是自己去Parse一个文本文件;尽量用RegExp,而不是自己从头操作字符串,等等等等。这就是“软件 复用”的体现。 

 

35. 你们会隔一段时间就停下来夯实代码么? 

要。最好一个月左右一次。传言去年年初Windows组在Stevb的命令下停过一个月增强安全。Btw,“夯”这个字念“hang”,第一声。 

 

36. 你们的项目组每个人都写Daily Report么? 

要写。五分钟就够了,写10句话左右,告诉自己小组的人今天我干了什么。一则为了沟通,二则鞭策自己(要是游手好闲一天,自己都会不好意思写的)。 

 

37. 你们的项目经理会发出Weekly Report么? 

要。也是为了沟通。内容包括目前进度,可能的风险,质量状况,各种工作的进展等。 

 

38. 你们项目组是否至少每周全体开会一次? 

要。一定要开会。程序员讨厌开会,但每个礼拜开会时间加起来至少应该有4小时。包括team meeting, spec review meeting, bug triage meeting。千万别大家闷头写code。 

 

39. 你们项目组的会议、讨论都有记录么? 

会前发meeting request和agenda,会中有人负责主持和记录,会后有人负责发meeting minutes,这都是effective meeting的要点。而且,每个会议都要形成agreements和action items。 

 

40. 其他部门知道你们项目组在干什么么? 

要发一些Newsflash给整个大组织。Show your team’s value。否则,当你坐在电梯里面,其他部门的人问:“你们在干嘛”,你回答“ABC项目”的时候,别人全然不知,那种感觉不太好。 

 

41. 通过Email进行所有正式沟通 

Email的好处是免得抵赖。但也要避免矫枉过正,最好的方法是先用电话和当面说,然后Email来确认。 

 

42. 为项目组建立多个Mailing Group 

如 果在AD+Exchange里面,就建Distribution List。比如,我会建 ABC Project Core Team,ABC Project Dev Team,ABC Project All Testers,ABC Project Extended Team 等等。这样发起Email来方便,而且能让该收到email的人都收到、不该收到不被骚扰。 

 

43. 每个人都知道哪里可以找到全部的文档么? 

应该每个人都知道。这叫做知识管理(Knowledge Management)。最方便的就是把文档放在一个集中的File Share,更好的方法是用Sharepoint。 

 

44. 你做决定、做变化时,告诉大家原因了么? 

要 告诉大家原因。Empower team member的手段之一是提供足够的information,这是MSF一开篇的几个原则之一。的确如 此,tell me why是人之常情,tell me why了才能有understanding。中国人做事喜欢搞限制,限制信息,似乎能够看到某一 份文件的人就是有身份的人。大错特错。权威、权力,不在于是不是能access information/data,而在于是不是掌握资源。 

 

45. Stay agile and expect change 

要这样。需求一定会变的,已经写好的代码一定会被要求修改的。做好心理准备,对change不要抗拒,而是expect change。 

 

46. 你们有没有专职的软件测试人员? 

要有专职测试。如果人手不够,可以peer test,交换了测试。千万别自己测试自己的。 

 

47. 你们的测试有一份总的计划来规定做什么和怎么做么? 

这就是Test Plan。要不要做性能测试?要不要做Usability测试?什么时候开始测试性能?测试通过的标准是什么?用什么手段,自动的还是手动的?这些问题需要用Test Plan来回答。 

 

48. 你是先写Test Case然后再测试的么? 

应该如此。应该先设计再编程、先test case再测试。当然,事情是灵活的。我有时候在做第一遍测试的同时补上test case。至于先test case再开发,我不喜欢,因为不习惯,太麻烦,至于别人推荐,那试试看也无妨。 

 

49. 你是否会为各种输入组合创建测试用例? 

不要,不要搞边界条件组合。当心组合爆炸。有很多test case工具能够自动生成各种边界条件的组合——但要想清楚,你是否有时间去运行那么多test case。 

 

50. 你们的程序员能看到测试用例么? 

要。让Dev看到Test Case吧。我们都是为了同一个目的走到一起来的:提高质量。 

 

51. 你们是否随便抓一些人来做易用性测试? 

要这么做。自己看自己写的程序界面,怎么看都是顺眼的。这叫做审美疲劳——臭的看久了也就不臭了,不方便的永久了也就习惯了。 

 

52. 你对自动测试的期望正确么? 

别期望太高。依我看,除了性能测试以外,还是暂时先忘掉“自动测试”吧,忘掉WinRunner和LoadRunner吧。对于国内的软件测试的现状来说,只能“矫枉必须过正”了。 

 

53. 你们的性能测试是等所有功能都开发完才做的么? 

不能这样。性能测试不能被归到所谓的“系统测试”阶段。早测早改正,早死早升天。 

 

54. 你注意到测试中的杀虫剂效应了么? 

虫子有抗药性,Bug也有。发现的新Bug越来越少是正常的。这时候,最好大家交换一下测试的area,或者用用看其他工具和手法,就又会发现一些新bug了。 

 

55. 你们项目组中有人能说出产品的当前整体质量情况么? 

要有。当老板问起这个产品目前质量如何,Test Lead/Manager应该负责回答。 

 

56. 你们有单元测试么? 

单元测试要有的。不过没有单元测试也不是不可以,我做过没有单元测试的项目,也做成功了——可能是侥幸,可能是大家都是熟手的关系。还是那句话,软件工程是非常实践、非常工程、非常灵活的一套方法,某些方法在某些情况下会比另一些方法好,反之亦然。 

 

57. 你们的程序员是写完代码就扔过墙的么? 

大忌。写好一块程序以后,即便不做单元测试,也应该自己先跑一跑。虽然有了专门的测试人员,做开发的人也不可以一点测试都不做。微软还有Test Release Document的说法,程序太烂的话,测试有权踢回去。 

 

58. 你们的程序中所有的函数都有输入检查么? 

不要。虽然说做输入检查是write secure code的要点,但不要做太多的输入检查,有些内部函数之间的参数传递就不必检查输入了,省点功夫。同样的道理,未必要给所有的函数都写注释。写一部分主要的就够了。 

 

59. 产品有统一的错误处理机制和报错界面么? 

要 有。最好能有统一的error message,然后每个error message都带一个error number。这样,用户可以自己根据 error number到user manual里面去看看错误的具体描述和可能原因,就像SQL Server的错误那样。同样,ASP.NET也要 有统一的Exception处理。可以参考有关的Application Block。 

 

60. 你们有统一的代码书写规范么? 

要有。Code Convention很多,搞一份来发给大家就可以了。当然,要是有FxCop这种工具来检查代码就更好了。 

 

61. 你们的每个人都了解项目的商业意义么? 

要。这是Vision的意思。别把项目只当成工作。有时候要想着自己是在为中国某某行业的信息化作先驱者,或者时不时的告诉team member,这个项目能够为某某某国家部门每年节省多少多少百万的纳税人的钱,这样就有动力了。平凡的事情也是可以有个崇高的目标的。 

 

62. 产品各部分的界面和操作习惯一致么? 

要这样。要让用户觉得整个程序好像是一个人写出来的那样。 

 

63. 有可以作为宣传亮点的Cool Feature么? 

要。这是增强团队凝聚力、信心的。而且,“一俊遮百丑”,有亮点就可以掩盖一些问题。这样,对于客户来说,会感觉产品从质量角度来说还是acceptable的。或者说,cool feature或者说亮点可以作为质量问题的一个事后弥补措施。 

 

64. 尽可能缩短产品的启动时间 

要这样。软件启动时间(Start-Up time)是客户对性能好坏的第一印象。 

 

65. 不要过于注重内在品质而忽视了第一眼的外在印象 

程序员容易犯这个错误:太看重性能、稳定性、存储效率,但忽视了外在感受。而高层经理、客户正相反。这两方面要兼顾,协调这些是PM的工作。 

 

66. 你们根据详细产品功能说明书做开发么? 

要这样。要有设计才能开发,这是必须的。设计文档,应该说清楚这个产品会怎么运行,应该采取一些讲故事的方法。设计的时候千万别钻细节,别钻到数据库、代码等具体实现里面去,那些是后面的事情,一步步来不能着急。 

 

67. 开始开发和测试之前每个人都仔细审阅功能设计么? 

要做。Function Spec review是用来统一思想的。而且,review过以后形成了一致意见,将来再也没有人可以说“你看,当初我就是反对这么设计的,现在吃苦头了吧” 

 

68. 所有人都始终想着The Whole Image么? 

要这样。项目里面每个人虽然都只是在制造一片叶子,但每个人都应该知道自己在制造的那片叶子所在的树是怎么样子的。我反对软件蓝领,反对过分的把软件制造看成流水线、车间。参见第61条。 

 

69. Dev工作的划分是单纯纵向或横向的么? 

不能单纯的根据功能模块分,或者单纯根据表现层、中间层、数据库层分。我推荐这么做:首先根据功能模块分,然后每个“层”都有一个Owner来Review所有人的设计和代码,保证consistency。 

 

70. 你们的程序员写程序设计说明文档么? 

要。不过我听说微软的程序员1999年以前也不写。所以说,写不写也不是绝对的,偷懒有时候也是可以的。参见第56条。 

 

71. 你在招人面试时让他写一段程序么? 

要的。我最喜欢让人做字符串和链表一类的题目。这种题目有很多循环、判断、指针、递归等,既不偏向过于考算法,也不偏向过于考特定的API。 

 

72. 你们有没有技术交流讲座? 

要的。每一两个礼拜搞一次内部的Tech Talk或者Chalk Talk吧。让组员之间分享技术心得,这笔花钱送到外面去培训划算。 

 

73. 你们的程序员都能专注于一件事情么? 

要 让程序员专注一件事。例如说,一个部门有两个项目和10个人,一种方法是让10个人同时参加两个项目,每个项目上每个人都花50%时间;另一种方法是5个 人去项目A,5个人去项目B,每个人都100%在某一个项目上。我一定选后面一种。这个道理很多人都懂,但很多领导实践起来就把属下当成可以任意拆分的资 源了。 

 

74. 你们的程序员会夸大完成某项工作所需要的时间么? 

会的,这是常见的,尤其会在项目后期夸大做某个change所需要的时间,以次来抵制change。解决的方法是坐下来慢慢磨,磨掉程序员的逆反心理,一起分析,并把估算时间的颗粒度变小。 

 

75. 尽量不要用Virtual Heads 

最 好不要用Virtual Heads。Virtual heads意味着resource is not secure,shared resource 会降低resource的工作效率,容易增加出错的机会,会让一心二用的人没有太多时间去review spec、review design。一个 dedicated的人,要强过两个只能投入50%时间和精力的人。我是吃过亏的:7个part time的tester,发现的Bug和干的活,加起来 还不如两个full-time的。参见第73条。73条是针对程序员的,75条是针对Resource Manager的。

<2>:关于程序员:

程序员从初级到中级10个秘诀

Justin James曾发表过一篇博文 《10 tips for advancing from a beginner to an intermediate developer》,为我们 分享如何才能完成程序员从初级到中级的蜕变,现将中文译文转载于此,供大家借鉴。  在一封与TechRepublic会员交流的邮件当中,他提到了面向 程序员的博客、文章及杂志分成两类:面向初学者类(“hello world”这种类型的教程)以及面向专家类(MSDN杂志)。这个观点很好,有关程序 员如何从初级跃升到中级的信息极少。以下是为了实现这种转变需要你去做的10件事。

1.学习另一门语言  其 实你学的是哪一门语言并没有关系,但是学习另一门语言(不管你已经了解多少种语言)将把你打造为更好的程序员。能学会一门与你日常使用的语言风格迥异 的 语言则更佳。打个比方,如果你是C#程序员,学习VB.NET或者Java对你的帮助就没有学习Ruby或者Groovy大。  我说“学另一门语 言”的意思是要真正学会它。学习一门语言包括三个领域的知识:语法、内置操作符和库,以及“如何使用”。前面两个简单;我认为一名有经验 的程序员,根据 语言的不同,能在半小时到几小时内掌握足以维护代码的语法知识。操作符和库只不过是知识逐步积累的过程,你什么时候想清楚要了解什么了,再 去查阅参考材 料也不迟。只有第三项,“如何使用它”-要花上你几个月的时间去跟这门语言打交道,真正的奇迹就在此发生。我建议用这门语言的风格去做一个适 合该语言的 项目。  真正学会了另一门语言之后,我敢保证你的程序员水平一定会突飞猛进。  

2.学习先进的搜索技术、手段和及策略  作 为一名好的程序员,不仅仅是技能的问题了,而是你寻找信息的技巧,这个趋势越来越明显。对大部分人而言,仅仅输入“现代语言及开发框架”,这都是泛泛 之 谈,记不住多少的。因此,你完成工作的能力通常取决于你的检索能力。不幸的是,了解到如何找到准确而高质量的信息可不仅仅是跑到 TechRepublic 来找答案,或者在你选好的搜索引擎上敲几个字那么简单。  “技术(Techniques)”、“手段(tactics)”和 “策略(strategies)”看起来是一回事,实际上并非如此。你需要学会的技术是 掌握你喜爱的搜索引擎的高级搜索系统;你需要了解诸如布尔操作符,如何过滤结果(像“非”关键字,域限制等等),关键字的词序扮演什么角色,等等。一句 话,RTFM(Read The Fucking Manual,读那些他妈的手册)吧。  你应该学会这些手段,诸如如何接近特定的搜索,以及了解 自己实际上想查些什么。查错误很容易—只需查出错代码即可—但是许多搜索的关键字选择要困难得多。  至于策略,你需要学会的东西,包括像应该使用哪种搜 索引擎(提示:普通的搜索引擎不一定就是最佳选择),使用普通搜索引擎前应该访问哪个网站,甚至是应该 到哪个论坛去寻求帮助,等等。 

3.帮助别人  教别人始终是学习一切东西的最好方法之一。相对而言,由于你在开发领域还是个新手,认为自己没什么可教给人家的,这可以理解。但这毫无意义。记住,你所 学 到的一切都是你从别人或别处学到的;因此请尝试一下,成为另外一个人要请教的“别人”。每天尽量花一点时间试着回答TechRepublic上的问 题,其 他网站的亦可。读读其他会员的回答,你也可以学到很多东西。  

4.有耐心,常练习  研究表明,要成为一名“专家”,需要花费10年,或者10000到20000小时的刻意练习时间。真的很久。还有,成为专家不尽然就是执行10年同样的 任 务;通常这意味着要在特定领域内执行广泛的任务。需要花费大量的时间和精力才能成为“专家”;做几年程序员是不够的。想在30岁左右成为一名高级软件开发 工程师?要么尽早接受教育/培训,要么你得愿意在闲暇时间进行大量的工作、阅读和练习。我从高中开始编程,还牺牲了许多休息时间去跟踪行业发展、学习新技 能等等。结果,我获得中级和高级程序员的时间就比我的大部分同事都要早得多,随着时间的推移,这些就转化成为很多的金钱。  

5.对教条拒之门外  是 时候开诚布公了:也许初级程序员了解的东西还不足以说出做某件事情有一种最好的方式。尊重朋友或者权威的观点是好的,但直到你更有经验之前,不要把他们 的观点说成是你自己的。很简单,如果你所了解的不足以让你独立地找出这些东西来,你又怎么会认为你知道哪一位“专家”是对的呢?话是难听了点,不过请 相信 我;由于受某些愚蠢建议的蛊惑,或者追随某些根本不知道自己在说些什么的所谓专家,白白把自己的职业生涯耽搁了几年,这样毛头小伙程序员,我见过多了。这 一点有一个很好的例子,就是面向对象结构的滥用。比如说,许多初级者读了一些有关面向对象的信息后,突然间,他们那简单的应用程序的类图看起来就像埃菲尔 铁塔一样了。  

6.深入学习一点先进理念  成为一名中级程序员,很大一部分是要在代码里面体现出一些所擅长的概念。就我而言,是多线程/并行性,是正则表达式,以及如何对动态语言进行变化(后两个 在我离Perl渐行渐远后开始退化)。这 是如何发生的?多线程和并行处理是因为我读了相关文章,觉得它看起来很有趣,然后再自己把它弄清楚了;然后我就一 直使用这些技术来写应用。我做过一件工 作,是用Perl写的,里面运用了大量的正则表达式。我也用一个过程引擎模板和内置数据库系统写过我自己的电子商务 引擎;那时我几乎花了2年时间在这上 面。  找到真正令你着迷的东西。也许是图像处理,也许是数据库设计,等等。即便你是一个入门级的程序员,也要尝试一下成为某一自己所关注领域的专家。这会让你相 当快速地进入到中级水平,一旦你到了那个水平,你的专家之路也走到一半了。  

7.学习你的领域里面的基本理论  写出“Hello  World”,跟理解那些字是如何显示到屏幕上的是两码事。通过学习支撑你所从事的工作的“基础/底层工作 (groundwork)”,你会变得更加在 行。为什么?因为你会理解事物为何会以这种方式运作,当东西坏了就能知道是哪里的问题,等等。通过掌握工作的底层机制,你变会得更出色。  如果你是Web程序员,读读HTTP  RFC和HTML规范。如果你使用代码生成器,好好看看它生成的代码;如果你使用数据库工具,看看它生成的底层SQL语句,不一而足。  

8.看看高级程序员的代码  在工作中看看高级程序员写的代码,然后问一问事情是如何以某种特别的方式完成的,为什么?可能的话看看开源的项目。甚至即使其他程序员没有最好的编程习 惯,你也会 学到许多编程经验。当然,要小心别学到坏习惯。我的意思是说不要生搬硬套人家的东西;你要能领会到哪些是能行的通的,哪些是有道理的,然后再模 仿人 家。  

9.学习好的习惯  愚蠢的变量名,糟糕的缩进习惯以及其他一些凌乱的迹象就是一个没有经验的程序员的最好标记。一个程序员在学会如何编程时,却经常没有被传授到那些不那么有 趣的细节,像代码格式编排。甚至尽管学习这些东西并不会令你的代码更好,也不会令你成为更好的程序员,它也会确保你不被同事视为入门级的程序员。甚至即使 某人是高级程序员,如果他的变量是以他那97只猫的名字来命名,或 者其函数叫做“doSomething()”的,他们看起来也不像是知道自己在干什么的 人。而且会令其代码在过程中更难以维护。 

10.要玩的开心  想要痴迷于单调乏味的工作?痛恨工作吧。要想升级为中级程序员可不仅仅是为了拿到不断增长的工资不达目的誓不罢休,而是要真正享受工作。如果你不喜欢自 己 的工作,且还是初级程序员,你怎么会认为成为中级或高级程序员情况就会有所好转呢?换工作或改职业吧。反过来说,如果你喜爱所从事的工作,那就好!只要你 坚持下去,我保证你能成为一名更好的程序员。(Justin James)

<3>:关于软件设计:

 

一些软件设计的原则

 

​本文为大家介绍软件设计中的一些原则,都是经过长期经验总结出来的知识,每一个程序员都应该了解,相信对大家在进行软件设计的过程中会有很大帮助。

Don’t Repeat Yourself (DRY)
DRY 是一个最简单的法则,也是最容易被理解的。但它也可能是最难被应用的(因为要做到这样,我们需要在泛型设计上做相当的努力,这并不是一件容易的事)。它意味着,当我们在两个或多个地方的时候发现一些相似的代码的时候,我们需要把他们的共性抽象出来形一个唯一的新方法,并且改变现有的地方的代码让他们以一些合 适的参数调用这个新的方法。
参考:http://en.wikipedia.org/wiki/KISS_principle

Program to an interface, not an implementation
这是设计模式中最根本的哲学,注重接口,而不是实现,依赖接口,而不是实现。接口是抽象是稳定的,实现则是多种多样的。以后面我们会面向对象的SOLID原 则中会提到我们的依赖倒置原则,就是这个原则的的另一种样子。还有一条原则叫 Composition over inheritance(喜欢组合而不是继承),这两条是那23个经典设计模式中的设计原则。

Command-Query Separation (CQS)  – 命令-查询分离原则
查询:当一个方法返回一个值来回应一个问题的时候,它就具有查询的性质; 
命令:当一个方法要改变对象的状态的时候,它就具有命令的性质; 

通 常,一个方法可能是纯的Command模式或者是纯的Query模式,或者是两者的混合体。在设计接口时,如果可能,应该尽量使接口单一化,保证方法的行为严格的是命令或者是查询,这样查询方法不会改变对象的状态,没有副作用,而会改变对象的状态的方法不可能有返回值。也就是说:如果我们要问一个问题,那 么就不应该影响到它的答案。实际应用,要视具体情况而定,语义的清晰性和使用的简单性之间需要权衡。将Command和Query功能合并入一个方法,方 便了客户的使用,但是,降低了清晰性,而且,可能不便于基于断言的程序设计并且需要一个变量来保存查询结果。

在系统设计中,很多系统也是以这样原则设计的,查询的功能和命令功能的系统分离,这样有则于系统性能,也有利于系统的安全性。

参考:http://en.wikipedia.org/wiki/Command-query_separation

You Ain’t Gonna Need It (YAGNI)
这个原则简而言之为——只考虑和设计必须的功能,避免过度设计。只实现目前需要的功能,在以后您需要更多功能时,可以再进行添加。

如无必要,勿增复杂性。 
软件开发先是一场沟通博弈。 

以前本站有一篇关于过度重构的文章,这个示例就是这个原则的反例。而,WebSphere的设计者就表示过他过度设计了这个产品。我们的程序员或是架构师在设计系统的时候,会考虑很多扩展性的东西,导致在架构与设计方面使用了大量折衷,最后导致项目失败。这是个令人感到讽刺的教训,因为本来希望尽可能延长项目的生命周期,结果反而缩短了生命周期。

参考:http://en.wikipedia.org/wiki/You_Ain%27t_Gonna_Need_It

Law of Demeter – 迪米特法则
迪 米特法则(Law of Demeter),又称“最少知识原则”(Principle of Least Knowledge),其来源于1987年荷 兰大学的一个叫做Demeter的项目。Craig Larman把Law of Demeter又称作“不要和陌生人说话”。在《程序员修炼之道》中讲 LoD的那一章叫作“解耦合与迪米特法则”。关于迪米特法则有一些很形象的比喻:
如果你想让你的狗跑的话,你会对狗狗说还是对四条狗腿说? 
如果你去店里买东西,你会把钱交给店员,还是会把钱包交给店员让他自己拿? 

和狗的四肢说话?让店员自己从钱包里拿钱?这听起来有点荒唐,不过在我们的代码里这几乎是见怪不怪的事情了。

对于LoD,正式的表述如下:



在《Clean Code》一书中,有一段Apache framework中的一段违反了LoD的代码:

final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();

这么长的一串对其它对象的细节,以及细节的细节,细节的细节的细节……的调用,增加了耦合,使得代码结构复杂、僵化,难以扩展和维护。

在 《重构》一书中的代码的环味道中有一种叫做“Feature Envy”(依恋情结),形象的描述了一种违反了LoC的情况。Feature Envy就 是说一个对象对其它对象的内容更有兴趣,也就是说老是羡慕别的对象的成员、结构或者功能,大老远的调用人家的东西。这样的结构显然是不合理的。我们的程序应该写得比较“害羞”。不能像前面例子中的那个不把自己当外人的店员一样,拿过客人的钱包自己把钱拿出来。“害羞”的程序只和自己最近的朋友交谈。这种情 况下应该调整程序的结构,让那个对象自己拥有它羡慕的feature,或者使用合理的设计模式(例如Facade和Mediator)。

参考:http://en.wikipedia.org/wiki/Principle_of_Least_Knowledge

面向对象的S.O.L.I.D 原则

一般来说这是面向对象的五大设计原则,但是,我觉得这些原则可适用于所有的软件开发。

Single Responsibility Principle (SRP) – 职责单一原则

关于单一职责原则,其核心的思想是:一个类,只做一件事,并把这件事做好,其只有一个引起它变化的原因。 单一职责原则可以看作是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。职责过多,可能引起它变化的原因就越多,这将导致职责依赖,相互之间就产生影响,从而极大的损伤其内聚性和耦合度。单一职责,通常意味着单一的功能,因此不要为一个模块实现过多 的功能点,以保证实体只有一个引起它变化的原因。

Unix/Linux是这一原则的完美体现者。各个程序都独立负责一个单一的事。 
Windows是这一原则的反面示例。几乎所有的程序都交织耦合在一起。 

Open/Closed Principle (OCP) – 开闭原则

关于开发封闭原则,其核心的思想是:模块是可扩展的,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的

对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。 
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。 

对 于面向对象来说,需要你依赖抽象,而不是实现,23个经典设计模式中的“策略模式”就是这个实现。对于非面向对象编程,一些API需要你传入一个你可以扩 展的函数,比如我们的C 语言的qsort()允许你提供一个“比较器”,STL中的容器类的内存分配,ACE中的多线程的各种锁。对于软件方面,浏览器的各种插件属于这个原则的实践。

Liskov substitution principle (LSP) – 里氏代换原则

软 件工程大师Robert C. Martin把里氏代换原则最终简化为一句 话:“Subtypes must be substitutable for their base types”。也就是,子类必须能够替换成它们的基类。即:子类应该可以替换任何基类能够出现的地方,并且经过替换以后,代码还能正常工作。另外,不应该在代码中出现if/else之类对子类类型进行判断的条件。里氏替换原则LSP是使代码符合开闭原则的一个重要保证。正是由于子类型的可替换性才使得父类型的模块在无需修改的情况下就可以扩展。

这 么说来,似乎有点教条化,我非常建议大家看看这个原则个两个最经典的案例——“正方形不是长方形”和“鸵鸟不是鸟”。通过这两个案例,你会明白《墨子 小 取》中说的 ——“娣,美人也,爱娣,非爱美人也….盗,人也;恶盗,非恶人也。”——妹妹虽然是美人,但喜欢妹妹并不代表喜欢美人。盗贼是人,但讨厌盗贼也并不代表就讨厌人类。这个原则让你考虑的不是语义上对象的间的关系,而是实际需求的环境。

在很多情况下,在设计初期我们类之间的关系不是很明确,LSP则给了我们一个判断和设计类之间关系的基准:需不需要继承,以及怎样设计继承关系。

Interface Segregation Principle (ISP) – 接口隔离原则

接口隔离原则意思是把功能实现在接口中,而不是类中,使用多个专门的接口比使用单一的总接口要好。

举 个例子,我们对电脑有不同的使用方式,比如:写作,通讯,看电影,打游戏,上网,编程,计算,数据等,如果我们把这些功能都声明在电脑的抽类里面,那么,我们的上网本,PC机,服务器,笔记本的实现类都要实现所有的这些接口,这就显得太复杂了。所以,我们可以把其这些功能接口隔离开来,比如:工作学习接口,编程开发接口,上网娱乐接口,计算和数据服务接口,这样,我们的不同功能的电脑就可以有所选择地继承这些接口。

这个原则可以提升我们“搭积木式”的软件开发。对于设计来说,Java中的各种Event Listener和Adapter,对于软件开发来说,不同的用户权限有不同的功能,不同的版本有不同的功能,都是这个原则的应用。

Dependency Inversion Principle (DIP) – 依赖倒置原则

高层模块不应该依赖于低层模块的实现,而是依赖于高层抽象。

举 个例子,墙面的开关不应该依赖于电灯的开关实现,而是应该依赖于一个抽象的开关的标准接口,这样,当我们扩展程序的时候,我们的开关同样可以控制其它不同的灯,甚至不同的电器。也就是说,电灯和其它电器继承并实现我们的标准开关接口,而我们的开关产商就可不需要关于其要控制什么样的设备,只需要关心那个标 准的开关标准。这就是依赖倒置原则。

这就好像浏览器并不依赖于后面的web服务器,其只依赖于HTTP协议。这个原则实在是太重要了,社会的分工化,标准化都是这个设计原则的体现。

参考:http://en.wikipedia.org/wiki/Solid_(object-oriented_design)

Common Closure Principle(CCP)– 共同封闭原则
一 个包中所有的类应该对同一种类型的变化关闭。一个变化影响一个包,便影响了包中所有的类。一个更简短的说法是:一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。CCP原则就是把因为某个同样的原因而需要修改的所有类组合进一个包里。如果2个类从物理上或者从概念上联系得非常紧密,它们通常一起发生改变,那么它们应该属于同一个包。

CCP延伸了开闭原则(OCP)的“关闭”概念,当因为某个原因需要修改时,把需要修改的范围限制在一个最小范围内的包里。

参考:http://c2.com/cgi/wiki?CommonClosurePrinciple

Common Reuse Principle (CRP) – 共同重用原则
包 的所有类被一起重用。如果你重用了其中的一个类,就重用全部。换个说法是,没有被一起重用的类不应该被组合在一起。CRP原则帮助我们决定哪些类应该被放 到同一个包里。依赖一个包就是依赖这个包所包含的一切。当一个包发生了改变,并发布新的版本,使用这个包的所有用户都必须在新的包环境下验证他们的工作,即使被他们使用的部分没有发生任何改变。因为如果包中包含有未被使用的类,即使用户不关心该类是否改变,但用户还是不得不升级该包并对原来的功能加以重新 测试。

CCP则让系统的维护者受益。CCP让包尽可能大(CCP原则加入功能相关的类),CRP则让包尽可能小(CRP原则剔除不使用的类)。它们的出发点不一样,但不相互冲突。

参考:http://c2.com/cgi/wiki?CommonReusePrinciple

Hollywood Principle – 好莱坞原则
好 莱坞原则就是一句话——“don’t call us, we’ll call you.”。意思是,好莱坞的经纪人们不希望你去联系他们,而是他们会在需要的时候来联系你。也就是说,所有的组件都是被动的,所有的组件初始化和调用都由容器负责。组件处在一个容器当中,由容器负责管理。

简单的来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在:

1.不创建对象,而是描述创建对象的方式。 
2.在代码中,对象与服务没有直接联系,而是容器负责将这些联系在一起。

控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。

好 莱坞原则就是IoC(Inversion of Control)或DI(Dependency Injection )的基础原则。这个原则很像依赖倒置原则,依赖接口,而不是实例,但是这个原则要解决的是怎么把这个实例传入调用类中?你可能把其声明成成员,你可以通过构造函数,你可以通过函数参数。但 是 IoC可以让你通过配置文件,一个由Service Container 读取的配置文件来产生实际配置的类。但是程序也有可能变得不易读了,程序的性能也有可能还会下降。

参考:

[url]http://en.wikipedia.org/wiki/Hollywood_Principle [/url]
[url]http://en.wikipedia.org/wiki/Inversion_of_Control [/url]

High Cohesion & Low/Loose coupling & – 高内聚, 低耦合
这个原则是UNIX操作系统设计的经典原则,把模块间的耦合降到最低,而努力让一个模块做到精益求精。

内聚:一个模块内各个元素彼此结合的紧密程度 
耦合:一个软件结构内不同模块之间互连程度的度量 

内聚意味着重用和独立,耦合意味着多米诺效应牵一发动全身。

参考:

http://en.wikipedia.org/wiki/Coupling_(computer_science)
[url]http://en.wikipedia.org/wiki/Cohesion_(computer_science) [/url]

Convention over Configuration(CoC)– 惯例优于配置原则
简 单点说,就是将一些公认的配置方式和信息作为内部缺省的规则来使用。例如,Hibernate的映射文件,如果约定字段名和类属性一致的话,基本上就可以不要这个配置文件了。你的应用只需要指定不convention的信息即可,从而减少了大量convention而又不得不花时间和精力啰里啰嗦的东东。 配置文件很多时候相当的影响开发效率。

Rails 中很少有配置文件(但不是没有,数据库连接就是一个配置文件),Rails 的 fans号称期开发效率是 java 开发的 10 倍,估计就是这个原因。Maven也使用了CoC原则,当你执行mvn -compile命令的时 候,不需要指源文件放在什么地方,而编译以后的class文件放置在什么地方也没有指定,这就是CoC原则。

参考:http://en.wikipedia.org/wiki/Convention_over_Configuration

Separation of Concerns (SoC) – 关注点分离
SoC 是 计算机科学中最重要的努力目标之一。这个原则,就是在软件开发中,通过各种手段,将问题的各个关注点分开。如果一个问题能分解为独立且较小的问题,就是相对较易解决的。问题太过于复杂,要解决问题需要关注的点太多,而程序员的能力是有限的,不能同时关注于问题的各个方面。正如程序员的记忆力相对于计算机知 识来说那么有限一样,程序员解决问题的能力相对于要解决的问题的复杂性也是一样的非常有限。在我们分析问题的时候,如果我们把所有的东西混在一起讨论,那么就只会有一个结果——乱。

我记得在上一家公司有一个项目,讨论就讨论了1年多,项目本来不复杂,但是没有使用SoC,全部的东西混为一谈,再加上一堆程序员注入了各种不同的观点和想法,整个项目一下子就失控了。最后,本来一个1年的项目做了3年。

实 现关注点分离的方法主要有两种,一种是标准化,另一种是抽象与包装。标准化就是制定一套标准,让使用者都遵守它,将人们的行为统一起来,这样使用标准的人就不用担心别人会有很多种不同的实现,使自己的程序不能和别人的配合。Java EE就是一个标准的大集合。每个开发者只需要关注于标准本身和他所在做的事情就行了。就像是开发镙丝钉的人只专注于开发镙丝钉就行了,而不用关注镙帽是怎么生产的,反正镙帽和镙丝钉按标来就一定能合得上。不断地把程序的某些部 分抽像差包装起来,也是实现关注点分离的好方法。一旦一个函数被抽像出来并实现了,那么使用函数的人就不用关心这个函数是如何实现的,同样的,一旦一个类被抽像并实现了,类的使用者也不用再关注于这个类的内部是如何实现的。诸如组件,分层,面向服务,等等这些概念都是在不同的层次上做抽像和包装,以使得使 用者不用关心它的内部实现细节。

说白了还是“高内聚,低耦合”。

参考:http://sulong.me/archives/99

Design by Contract (DbC) – 契约式设计
DbC的核心思想是对软件系统中的元素之间相互合作以及“责任”与“义务”的比喻。这种比喻从商业活动中“客户”与“供应商”达成“契约”而得来。例如:

供应商必须提供某种产品(责任),并且他有权期望客户已经付款(权利)。 
客户必须付款(责任),并且有权得到产品(权利)。 
契约双方必须履行那些对所有契约都有效的责任,如法律和规定等。

同样的,如果在程序设计中一个模块提供了某种功能,那么它要:

期望所有调用它的客户模块都保证一定的进入条件:这就是模块的先验条件(客户的义务和供应商的权利,这样它就不用去处理不满足先验条件的情况)。 
保证退出时给出特定的属性:这就是模块的后验条件——(供应商的义务,显然也是客户的权利)。 
在进入时假定,并在退出时保持一些特定的属性:不变式。 

契约就是这些权利和义务的正式形式。我们可以用“三个问题”来总结DbC,并且作为设计者要经常问:

它期望的是什么? 
它要保证的是什么? 
它要保持的是什么? 

根 据Bertrand Meyer氏提出的DBC概念的描述,对于类的一个方法,都有一个前提条件以及一个后续条件,前提条件说明方法接受什么样的参数数据等,只有前提条件得到满足时,这个方法才能被调用;同时后续条件用来说明这个方法完成时的状态,如果一个方法的执行会导致这个方法的后续条件不成立,那么 这个方法也不应该正常返回。

现在把前提条件以及后续条件应用到继承子类中,子类方法应该满足:

1.前提条件不强于基类. 
2.后续条件不弱于基类. 

换 句话说,通过基类的接口调用一个对象时,用户只知道基类前提条件以及后续条件。因此继承类不得要求用户提供比基类方法要求的更强的前提条件,亦即,继承类方法必须接受任何基类方法能接受的任何条件(参数)。同样,继承类必须顺从基类的所有后续条件,亦即,继承类方法的行为和输出不得违反由基类建立起来的任 何约束,不能让用户对继承类方法的输出感到困惑。

这样,我们就有了基于契约的LSP,基于契约的LSP是LSP的一种强化。

参考:http://en.wikipedia.org/wiki/Design_by_contract

Acyclic Dependencies Principle (ADP) – 无环依赖原则
包 之间的依赖结构必须是一个直接的无环图形,也就是说,在依赖结构中不允许出现环(循环依赖)。如果包的依赖形成了环状结构,怎么样打破这种循环依赖呢?有 2种方法可以打破这种循环依赖关系:第一种方法是创建新的包,如果A、B、C形成环路依赖,那么把这些共同类抽出来放在一个新的包D里。这样就把C依赖A 变成了C依赖D以及A依赖D,从而打破了循环依赖关系。第二种方法是使用DIP(依赖倒置原则)和ISP(接口分隔原则)设计原则。

无环依赖原则(ADP)为我们解决包之间的关系耦合问题。在设计模块时,不能有循环依赖。

参考:http://c2.com/cgi/wiki?AcyclicDependenciesPrinciple

<4>:关于工作:

每天写出好代码的5个建议

成为一个优秀的程序员和成为其他优秀的专业人员一样,需要尽可能多的做一些有质量的工作。有句很流行的话可以总结:做,正确做事,立马就做。(Do it. Do it right. Do it right now)

0. 将一天要做的事情列成清单

  完成复杂活动(activity)的最好方法是将其拆分成简单的各项活动。每天早上,将你一天要完成的活动进行拆分,然后制定一个相应的日程安排表,这样能够帮助你:

  • 更好的理解这个活动。
  • 每天都有一个集中的目标。
  • 提高你的估计能力,几天之后,你会发现你能预测一天的工作量。

 

  1. 一次只做一件事

  集中于一项任务比同时做多项任务更多产,不同的研究已经证明这个观点,并且发布在不同的媒体上(例如CNN)。

  集中精力工作25分钟,休息5到10分钟。你可以用诸如“番茄工作法”这种流行的技术来帮助你管理时间。还有工具能帮助你测量你花在各项不同任务上的时间,我最喜欢的是CoolTimer,这里也有10个不错的时间追踪应用程序。

  2. 正确做事

  以下两个是考察事情是否正确完成的关键:

  • 要为解决方法感到到自豪,因为这不仅仅只是个普通的解决方法,这是个好的方法。遵循“软件质量金字塔”的原则
  • 解决方法至少要经过一次检查。在你的同事中,请一位你尊敬的优秀开发人员检查你的方法,并接受他的真诚建议。

 

  3. 不要半途而废

   众所周知,若仍有一个玻璃杯需要清洗,则不能说已经洗完了。粉刷墙壁或驱车前往某处这些事情上我们也认可同样的道理,但在软件开发上我们却不这么认为了。即便我们没有完成所有的单元测试,或者我们没有核实实现方式是否符合用户的需要,我们也说完成了任务。这是典型来自 Hope DrivenDevelopment的行为,是非常有害的。

  需求没有更改时,只有当你百分之百确认再也没有必要改善那个解决方法时,才能算完成任务。

  4. 与其道歉,不如补救,而放弃最不可取。

   如果你要花额外的时间来完成一些代码的测试,或者重构不可读的类,那么就去做,因为这是为将来投资时间。但是如果你在某件事上面卡住了或者将项目拖延的太久,那么寻找一个更容易的方案。它可能不如你目前正在实现的方案优雅,但至少你有方案。确保记录下来以应对这个项目将来的风险,并且有些东西需要重新审查。

 

<5>:关于工作环境:

程序员的工作效率和工作环境

1、足够大的桌面空间
程序员的办公桌最好可以并排坐下2人,以便结对编程或者code review。在不离开座位的情况下,有足够空间用白板或者纸面展开讨论问题。协作的同事不必站在身后费力的越过肩膀来看屏幕上的内容。桌面可以放下2个显示器并可以随 手拿到常用的参考资料及书籍,有合适的文件柜或壁柜存放归档的资料,避免桌面上堆满了各种打印的资料。

2、电脑环境
工 作的机器有足够的内存,比如8G,这样并行打开复杂的workspace时候不需要关闭邮件或者浏览器软件,也避免在debug模式时硬盘在拼 命 swap以腾出空余内存。办公环境有足够的带宽,访问Google的服务没有障碍。内部资源如测试服务器、邮件服务器、SVN访问要非常快。    
3、座位距离
多人的team中尽量能让所有工位之间行走距离最短,避免坐在对面的两个员工需要绕一大圈才能到达对方电脑前。    
4、其他环境
温度及空气状况,办公室不要过冷或者过热。空气质量清新,不要有明显噪音,比如来自空调、日光灯、服务器等噪音。    
其他一些可选条件
— 程序员最好有两个显示器,或建议1台式机+1笔记本,可以极大提高开发效率    
— 有合适的、方便更新的公告栏    
— 有公共休闲区,比如一些游戏区域,方便互相交流,发散讨论    
— Joel推崇的Aeron电脑椅    
— 陈旧的办公环境会让面试者或者来访客户印像不佳,办公环境最好有定期维护保养并适当淘汰旧的设备。发暗的地毯、电脑椅上擦不掉的污渍,偏小的电脑屏幕、油光发亮的键盘都会让求职者印像不佳。    
— 有合适的参考图书库,可以找到常用资料    
—有合适的咖啡、碳酸饮料、零食   

你可能感兴趣的:(软件编程之美)