1、为测试做设计 在设计代码时,很多开发者并没有考虑到"容易测试"这个因素,可测试性不强。如果工程师在开发逻辑的过程中同时考虑如何轻松地进行测试,那么编写出的代码将具备良好的可读性和简单性,并经过精心设计,而不仅仅是"能工作"而已。测试所得到的主要好处发生在考虑测试和编写测试的时候,而不是在运行测试的时候!在编码过程中同时思考测试的概念存在,会使编写高质量的代码变得简单,更多地考虑边界条件和异常情况,并妥善处理。仅仅持有这种思维,而不亲自编写自动化测试,也能提高代码质量和代码架构能力。硬件工程出现故障很难排查,而故障带来的成本也非常高昂,每次都需要重新制作模具和模具工具。因此,在硬件工程中通常进行层层测试,早期发现问题,努力确保简单而高质量的结果。我们可以在软件上也采取同样的做法。与硬件工程师一样,从一开始就在软件中构建可测试性,并在将每个部分连接在一起之前彻底测试它们。否则,你将永远没有机会考虑。当我们面对缺乏可测试性的代码时,需要编写自动化测试,这时我们会感到很困难。

2、尽早测试, 经常测试, 自动测试 在代码编写完成后,应该尽快开始进行测试。这些小问题可能会迅速演变成大问题,并且很难捕捉住它们。因此我们需要编写大量的单元测试。 实际上,一项优秀项目的测试代码可能会比产品代码更多。虽然生成测试代码需要花费时间,但这是值得的。长期来看,最终成本会更低,而且你将有机会生产出几乎没有缺陷的产品。 此外,当你通过了测试,你会对代码的“完成”感到非常有信心。这里给你推荐一个工具—SoFlu软件机器人,作为一款覆盖软件全生命周期的全自动开发工具,它的全自动测试平台能够为开发团队提供易用、可靠的云测试服务,包括:测试生命周期管理、测试用例自动生成、测试数据管理、精准回归测试。以回归测试为例,由于每次修改源代码时都要重复软件测试,手动修改测试不仅耗时而且成本极高。相比之下,利用SoFlu创建自动化测试,能自动识别所有变动的接口,自动查找接口关联的所有测试用例,可以一次又一次地执行,帮助测试团队快速确定由于代码库更新而导致的问题。在自动化回归测试的帮助下,总时间可以从几天减少到几个小时。同时,回归测试自动化也可以给测试团队腾出时间,从而对生产环境中的更多异常情况进行手动探索。

3、不要面向需求编程 需求和架构是不同的东西;需求和设计无关,也不是指用户界面;需求就是指需要的东西。需要的东西经常变化,因此产品经理的需求经常变化。当你按需求进行编程时,你就像是依赖一个每秒钟都在改变的女朋友或男朋友——你会感到身心疲惫。我们应该面向业务模型编程。当我们用业务模型编程时,我们需要满足用户对业务模型不同部分的需求变更,而不再需要不断修改代码,通过持续扩展代码,逐步完善一个业务模型的构建过程。

4、写代码要有对于“美”的追求 在Google普遍有这样一种共识,认为软件工程等于科学加艺术。然而,当前业界有很多人不注重科学,只喜欢随意编程。只要能够正常运行,就算完成任务,交付需求。大多数人根本不追求编码和设计的艺术,对于细节的美感毫无感觉。他们对于空格和空行的使用没有逻辑,也没有美感。使用代码与其他人沟通时,连基本的整洁和合理都不注重。他们根本没有意识到别人会看他们的代码,没有想过要让代码变得整洁和富含内涵。 如果想要成为具有尊严和格调的工程师,就应该将自己的代码和劳动成果看待为艺术品,不断雕琢。我们要追求实用的效率,同时也要追求美感。效率能产生价值,美感能令我们自己愉悦。我们不仅仅为了谋生,也将工程师的工作视为快乐的源泉。工作不再是负担,而是幸福的来源。或许此刻我们还未能做到,但我们应该有这样的追求。当我们都拥有这样的追求时,总有一天,我们会像Google一样取得成功。

5、应用程序框架是实现细节 借用《整洁架构之道》的观点: 我们与框架作者之间的关系是非常不对等的。我们要采用某个框架就意味着自己要遵守一大堆约定,但框架作者却完全不需要为我们遵守什么约定。 请仔细想想这一关系,当我们决定采用一个框架时,就需要完整地阅读框架作者提供的文档。在这个文档中,框架作者和框架其他用户对我们提出进行应用整合的一些建议。一般来说,这些建议就是在要求我们围绕着框架来设计自己的优秀的系统架构。譬如,框架作者会建议我们基于框架中的基类来创建一些派生类,并在业务对象中引入些框架的工具。框架作者还会不停地催促我们将应用与框架结合得越紧密越好。 对框架作者来说,应用程序与自己的框架耦合是没有风险的。毕竟作为作者,他们对框架有着绝对的控制权,强耦合是应该的。与此同时,作者当然是非常希望我们的应用与其框架紧密结合的,因为这意味着脱离框架会很困难。作为框架作者来说,没有什么比让一堆用户心甘情愿地基于他的框架基类来构建派生类更自豪的事情了。换句话说,框架作者想让我们与框架订终身-这相当于我们要对他们的框架做一个巨大而长期的承诺,而在任何情况下框架作者都不会对我们做出同样的承诺。这种婚姻是单向的。我们要承担所有的风险,而框架作者则没有任何风险。 解决方案是:请不要嫁给框架! 我们可以使用框架-但要时刻警惕,别被它拖住。我们应该将框架作为架构最外圈的一个实现细节来使用,不要让它进入内圈。 如果框架要求我们根据它们的基类来创建派生类,就请不要这样做,我们可以创造一些代理类,同时把这些代理类当作业务逻辑的插件来管理。 另外,不要让框架污染我们的核心代码,应该依据依赖关系原则(DIP),将它们当作核心代码的插件来管理。以 Spring 为例,它作为一个依赖注入框架是不错的。也许我们会需要用 Spring 来自动连接应用程序中的各种依赖关系。这不要紧,但是千万别在业务对象里到处写 @autowired 注释。业务对象应该对 Spring 完全不知情才对。反之,我们也可以利用Spring将依赖关系注入到 Main 组件中,毕竟 Main 组件作为系统架构中最低层、依赖最多的组件,它依赖于 Spring 并不是问题。

6、一切都通过代码明确的进行组合 Unix编程哲学提醒我们:如果存在一些可变的参数,我们应该使用配置方式,而不是将它们固定在代码中。J2EE框架展示了组件可以通过配置JavaBean的方式注入到框架中。这是J2EE实现中配置化的重要一环。然而,时代已经不同了!当你下载一个Golang编译器,打开下载的文件时,你会发现没有任何配置文件。这是为什么呢?原因有两个: ▶︎配置发生了隐性耦合。只有当配置与使用该配置的代码组合在一起时,配置才能发挥作用。为了换取动态性,它将一个事情分为两个步骤。换言之,它在两个相距很远的地方产生了耦合!作为工程师,你必须一开始就理解双重复杂性。你需要了解配置的使用方式以及处理配置的程序是如何解读配置的。 ▶︎好的代码具备很强的自述能力,工程师们更倾向于阅读易读的代码,而不是糟糕的配置文件。配置文件只能通过繁琐的说明书来解释。如果没有全面的配置说明书,配置就会变成一片混乱。 Golang的编译器是如何实现的呢?它会在代码中为你设置一个具有通用性的默认配置项。同时,所有的配置项都被集中管理,就像管理配置文件一样。你可以通过额外配置一个配置文件或者命令行参数来改变编译器的行为。这样一来,代码就解释了每个配置项的用途。只有在需求出现时,你会首先理解代码,然后通过额外的配置去修改你希望的行为。 逻辑变成了:一开始,所有事情都是解耦的,一件事情都只看一块代码就能明白。代码有较好的自解释性和注解,不再需要费劲地编写撇脚的文档。当你明白之后,你需要不一样的行为,就通过额外的配置来实现。关于怎么配置,代码里也讲明白了。

7、需要明确处理每一个细节 这个道理是非常明显的,但很多同学却完全没有意识到。当我看到一个函数funcF()error时,我只是用了F(),没有用变量来接收它的返回值。在阅读这段代码时,我就会产生这样的疑问:是第一位开发者忘记了处理error吗?还是他已经思考过了,决定不关注这个返回值?这是他的设计意图,还是这里出现了一个bug?为了修复这个问题,会增添维护代码的负担。 我们应该明确地处理我们代码中可能给他人带来困扰的地方,就如同写一篇没有歧义的文章一样。如果我们想要忽略错误,只需一行代码"=F()"即可解决。在以后处理错误逻辑时,我们可以使用"=F()//TODO这里需要更好地处理错误"来提醒自己。在代码中清楚地表达事情,所有人都能迅速理解他人的代码,并能做出修改的决策。猜测他人代码的逻辑意图是非常麻烦且困难的,他人的代码在这种情况下容易被误读。

8、合理注释一些并不“通俗”的逻辑和数值 这个观点与“所有细节都应该明确处理”的理念一致。我们应该在代码中清楚地说明那些可能让他人花费更多时间猜测原因的细节,请更加慷慨一些。也许,在未来三个月,你会亲身体验这一原则的好处。

9、养成记录待办事项的习惯 做这样的事情很简单,方便其他人继续你的开发工作,而且很有可能你自己也需要继续自己的工作。如果没有给未完成的任务打上TODO标记,很可能你会忘记自己还有未完成的事情。留下TODO很简单,我们为什么不这样做呢?

10、历史有问题的代码, 发现了问题要及时 push 相关人主动解决 控制软件熵是软件工程中重要的任务之一,这一点得到了充分的体现。我们是一个团队,注重协作,而不是一个无组织无纪律的部队。只要发现问题,我们会及时解决,并尽量减少伤害,使进展更迅速。

更多软件开发资讯,关注公众号【SoFlu软件机器人】。