Home 读《程序员的职业素养》:The Clean Coder
Post
Cancel
Preview Image

读《程序员的职业素养》:The Clean Coder

这几天看了《The Clean Coder》:A code of Conduct for Professional Programmers 这本书,是《Clean Code》这本书的作者所著,有一些自己认为颇为受益的点,这里分享给大家。

每个专业软件开发人员必须精通的事项

  • 设计模式。必须能描述 GOF 书中的全部 24 种模式,同时还要有 POSA 书中的多数模式的实战经验。
  • 设计原则。必须了解 SOLID 原则,而且要深刻理解组件设计原则。
  • 方法。必须理解 XP、Scrum、精益、看板、瀑布、结构化分析及结构化设计等。
  • 实践。必须掌握测试驱动开发、面向对象设计、结构化编程、持续集成和结对编程。
  • 工具。必须了解如何使用 UML 图、DFD 图、结构图、Petri 网络图、状态迁移图表、流程图和决策表。

拒绝和承诺

能就是能,不能就是不能,不要说“试试看”。

作为软件开发人员,我们经常会面对的情况就是对需求进行评估并估算时间,在这个过程中想必大家都会相对谨慎的进行考虑,并给自己留出一点浮动时间,最终产出一份开发计划,到这里问题并不大。下面来具体到其中的某一个任务上:

  • 如果产品经理想要增加一点额外工作而不改变交付时间,哪怕他坚持说只是增加一个文本框这样的简单功能,那么我们改怎么办呢?

    • 一口答应下来那绝对是愚蠢的,是极其不专业的行为,因为增加工作量一定会需要更多的时间,将会打乱原来的计划,给项目的按时交付带来风险;
    • 或者可能会说那我试试看吧,这就意味着你承认自己之前未尽全力,现在还有余力可施;
    • 或者想着我可以少写点测试,或者加加班,大量的经验告诉我们,牺牲专业原则以求全,并非问题的解决之道,舍弃这些原则,只会制造出更多的麻烦。

    作为专业的开发人员,不应该屈从于权势,应当有勇气说“不”,只有会说“不”字的专业人员,他作出的承诺才更有价值。

    那么这里应该怎么做呢?重新评估开发时间,让产品经理能够根据新的开发时间去安排计划,早做打算。

  • 另外一种情况是,我们已经承诺了这项任务会在5天内完成,可是在第2天遇到了意料之外的坑,这时应该怎么办呢?

    • 硬着头皮做下去,希望事情会有转机,这无异于在给项目增加风险,因为预估的时间并不包含处理某个坑,寄希望于某种运气并不靠谱;
    • 或者想着我可以少写点测试,或者加加班,这和上面的情况一样。

    如果你无法兑现承诺,那么最重要的就是尽早向你的承诺对象发出预警,越快越好,越早越好,让别人调整对你的预期,这样他们也好重新尽早改变计划。这里我们不妨想象一下,自己是铁路工人,承诺2个月内能把铁路修好,计划第3个月的第1天火车就会开过来,如果自己意识到了延期风险,却到了最后关头才告诉大家,这时就面临着大量乘客退票投诉风险,如果及早通知,那么工作人员就可以延迟开放购票,乘客们也会相应的尽早改变自己的计划。

结对编程

程序员编程时的状态,对于代码质量的影响是巨大的。书中列举了焦虑时、听音乐、时常被中断、完全没思路的阻塞状态等,都是不利于产出高质量代码的,还有一种状态:流态。

这是程序员在编写代码时会进入的一种意识高度专注但思维视野却会收拢到狭窄的状态,在这种状态下,他们会感到效率极高,在这种状态中,他们会感到绝无错误。因此他们一直苦苦追求进入这种状态,并经常以能在那种状态下维持多久来衡量自我价值。

之前虽不知道这个名词,但是我自己确实会经常有这种状态,在这种状态中会感觉一切代码逻辑都了如于心,输出效率非常之高,能够“自信”到一次编写完所有代码再运行,并确信绝无错误。书中提到流态也并非一种完美的状态,这其实只是一种“浅层冥想”状态,在这种状态下,为了追求所谓的速度,理性思考的能力会下降,其实放弃了顾全全局,因此我们也要去避免进入流态。

那么怎么样能够保证编程时的状态呢?结对编程!

结对编程时,任一方都不可能进入流态,并且如果遇到一方被中断的情况,那么另一方很容易将当时的上下文维护起来,并在你回来之后帮你恢复状态。如果你状态不好,没有思路或者理不清头绪,那么找一个搭档来结对吧,你们想法的碰撞,会让你渐入佳境,创造出好的代码来。

TDD

TDD在早期刚被提出时,还颇具争议,但是到现在,TDD的可行性和好处,已无可争议。

上面提到了如果你写代码时经常被打断,那么TDD也是一个很好的维护上下文状态的办法,当你回来继续编码时,看到尚未通过的测试,就知道自己该干什么了。为什么要先写测试再写实现呢?事后写的测试只是一种防守,而先行编写的测试则是进攻,它会迫使你去考虑什么是好的设计,因为坏的高耦合的代码,是很难被测试的。关于TDD的好处,这里就不详述了,网上有很多这样的文章,这里重点写一下TDD的三项法则:

  1. 在编好失败单元测试之前,不要编写任何产品代码;
  2. 只要有一个单元测试失败了,就不要再写测试代码,无法通过编译也是一种失败情况;
  3. 产品代码恰好能够让当前失败的单元测试成功通过即可,不要多写。

测试

验收测试

在开发中,各方(开发方、业务方、测试方)想要真正对需求理解一致,最终实现出来业务方想要的功能,真的非常困难,因此专业开发人员既要做好开发,也要做好沟通。这里非常有用的方法是编写验收测试,确保在开发之前大家对验收测试达成共识,这其实就是我们在敏捷实践中所做的 Kick off,在开发之前明确开发 Scope,细化需求,这样才能确定需求何时算完成,QA 才能在测试的时候更加明确。

我们一般使用的验收测试编写模版是 Given, When, Then, 例如:

Given: 根目录不存在文件夹 logs

When: 点击新建文件夹按钮

Then: 会在根目录创建一个空的名为 logs 的文件夹

单元测试是程序员写给程序员的,而验收测试则是写给业务方的,由业务方测试 “正确路径”,QA 测试 “错误路径”,边界条件、异常、例外情况。

测试策略

test

单元测试

单元测试通常由程序员使用与系统开发相同的语言编写,目的是在最底层去定义系统,确保程序员的代码意图被正确实现且没有随着代码的改动被破坏。

组件测试

组件测试是对组件封装的业务规则进行测试,一般是向组件中传入数据,然后收集输出数据。其中需要使用合适的 Mocking 等辅助技术,与系统其它组件解耦。组件测试主要测的是成功路径的情况,大多数异常由单元测试来覆盖。

集成测试

集成测试只对那些组件很多的较大系统才有意义,测试的是组件之间能够正常通信,它们并不会测试业务规则,因此它们其实是装配测试。

系统测试

系统测试是针对整个集成完毕的系统来进行的自动化测试,是最终的集成测试,应该包含吞吐率测试和性能测试,其目的不是要确保正确的系统行为,而是要确保正确的系统构造。

人工探索式测试

此类测试是要在验证预期行为的时候,探索系统预期之外的行为。探索型测试不是要证明每条业务规则、每条运行路径都正确,而是要确保系统在人工操作下表现良好,同时富有创造性地找出尽可能多的古怪之处。

预估

关于预估,不同的人对其有不同的看法,业务方觉得预估就是承诺,开发方认为预估就是猜测,两者相差迥异。当我们开发不能百分百有把握时,就不要作出承诺。

预估其实是一种类似于正态分布的概率分布,并不是个定数。我们预估的往往是那个均值,而乐观估计的最小时长和悲观估计的最大时长,也都是有可能发生的。书中提到了几种方法,这里介绍其中的两种:

PERT

全称是 Program Evaluation and Review Technique, 该方法比较适用于单人预估,对某项任务,会有三个预估数字:

  • O:乐观估计
  • N:标称估计
  • P:悲观估计

乐观估计和悲观估计都是最极端的情况,为了保证它们是有意义的,这个数字对应的发生概率都应该小于1%。得到三个数字之后,就可以计算出该项任务的期望完成时间了:

( O + 4N + P ) / 6 

标准差为:

( P - O ) / 6

比如一项任务的 O = 1, N = 3, P = 12, 那么大概完成时间需要 4.2 天,标准差大概是 1.8 天。标准差越大说明不确定性越大。

亮手指

该方法适合多人合作,一起估算时。大家围坐在桌旁,每次讨论一项任务,针对每项任务,都必须讨论清楚这个任务涉及什么,有哪些不确定因素,该怎么实现,然后主持人喊到 3,大家一起伸出1~5个手指,代表预估点数,这个点数具体对应到几天,可以事先商定好。

如果大家的预估很相似,那么可以按多数人的意见来;如果有人的预估和大家想差较大,那么可能是他考虑到了大家没考虑到的,或者有其他因素,这时一定要讨论清楚,然后重新预估,最终达成一致。这个方法最大的好处就是,别人可以看到你自己看不到的东西,大家聚在一起,就可以把问题看的更全面,使预估更精确。

在预估时,一定要把任务尽可能的拆分成小任务,这样不仅更利于理解任务,而且某一两个小任务的预估错误,相对所有任务来讲,不会对总的结果产生明显影响。

其他点

书中还提到了什么才是“专业”,专业人员需要不断练习,应该如何管理自己的时间,怎么避免和应对压力,怎么和他人更好的协作,怎么给团队调配项目,以及专业人员的理想成长过程等,如果大家感兴趣的话,可以翻看书籍。

This post is licensed under CC BY 4.0 by the author.

iOS 动态库 Dynamic library

读《大话数据结构》

Comments powered by Disqus.