走出软件开发法则

阅读 570
收藏 33
2016-09-28
原文链接:www.jianshu.com

如果你也是一名程序员,那么相信从你第一天学习编程起,就会被灌输很多关于软件开发中的法则,它们有些来自于课堂,有些来自于书本,还有些则来自于工作中前辈的教导。我们总是努力地去学习这些法则,然后再将它们传授给更多后来人。然而,我们是否只是不假思索地接受它们,而没有真正尝试着去理解过这些软件开发中的法则呢?在这篇文章里,我将尝试通过来自开发、测试以及流程3个不同方面的问题,谈谈我对这些软件开发法则的认知。


面向对象?

今天我们在软件开发时最常使用的编程语言,如Java、C++、Python、Swift等等,都无一例外地支持面向对象的编程特性。而那些有关程序员的招聘信息中,也几乎都能看到“具备面向对象的程序设计和开发能力”的要求。尽管大部分程序员都能熟练地背出面向对象编程的三大特性:继承、封装、多态,但似乎他们对面向对象的认识也仅仅停留在了这些概念以及某一种编程语言的实现语法上了。我之前曾提到自己在考察程序员时经常使用的方法,我会让应试者尝试用面相对象设计的方法来描述面试所在的房间,结果却发现大部分面试者无法给出令人满意的答案,甚至有些人完全没有思路。可见程序员们虽然都会在简历中写上自己精通面向对象编程,但实际却没并没能真正理解它,更别说使用面向对象的思想去解决问题了。

面向对象并不是一句假大空的口号,它其实为我们提供了一种思维方式,帮助我们更好地进行软件的构建、组织以及复用。但要想掌握这种思维方式却并不简单,这有点像我们都知道正确的价值观应该是怎样的,但一旦需要应用到自己身上却很难做到一样,面向对象的思维方式需要通过不断的实践运用才能获得。然而大部分程序员并没能这么做,或者说没有机会去进行更多的练习。今天的开发与以往相比已经大大简化了,那些底层需要复杂抽象的设计都有了可以直接拿来使用的框架,程序员要做的更多是基于这些框架去写业务实现逻辑。虽然开发变得更简单了,但这却在一定程度上减弱了我们的编程能力,也出现了很多程序员不会编程的事例。当我们需要运用面向对象的思维去进行分析和设计以解决那些复杂问题时,往往就会觉得力不从心,无法精准地完成它们。

我所看到另一个更让人担忧的问题是,很多程序员错误地认识了面向对象。例如,他们会想当然地认为,面向对象就是把任何实体描述为一个DTO(Data Transfer Object),用Getter,Setter方法去存取它们的属性,然后在其他业务组件中去处理它们。这的确是一个常见、也在大部分编程书籍中被作为代码示例的应用模式,但我想说DTO,你真的被滥用了。当你必须把所有实体看作DTO时,本身你的编程思维就受到了限制,你所开发的程序也将变得机械、缺乏扩展性,越来越难以维护。DTO只是面向对象中描述对象的一种形式,你应该以更高的纬度去判断一个实体应该如何表现。比如,数据库中的某一条记录,它既可以通过那些OR Mapping框架被映射为DTO,同样的,你也可以创造一个类似Record这样的键值对的类来表示它,而后一种往往在批量数据分析、报表加工等场景下更加合适。

我们需要具备面向对象的编程思维,但在我们没有真正拥有它之前,也千万不要被那些已有的原则、模式和框架束缚住你的思维,多看那些优秀的程序,并认真思考自己的每一次的程序设计,及时进行总结和反思,你将会从中逐渐获得超越面向对象本身的正确编程思维。

测试非常重要?

测试的重要性不言而喻,从倡导进行单元测试,到TDD(测试驱动开发),我们似乎对程序员进行严格的测试并保证代码质量有了越来越高的要求。今天,有很多开发团队都会要求程序员们采用TDD等方式来测试他们的代码,甚至还会通过测试覆盖率等指标来对程序员进行考核。这不禁让我想到,我的一位马来同事曾经为了满足公司代码注释行数要求,而把一行注释硬是拆成每个单词一行的趣事。我们是不是又一次为了满足某种教条而本末倒置地去做一些不那么必要的测试了呢?

  • 测试不是为了证明那些必然正确的东西:我始终认为程序员们自己是最明白哪些功能需要测试的。如果这一点是成立的,那又何必要求他们去为每一个功能或方法写测试案例,又或者让他们在开发之前就去编写完整的测试用例呢?测试一定是被用来证明特定需求是否得到满足的,你应该为那些可能存在不确定性的需求或者对外提供的服务来编写全面的测试案例,而不仅仅是为了满足测试覆盖率,去给那些明明知道必然正确的实现细节做测试。

  • 测试无法提高代码的质量也不会让代码更易于维护:有人说测试是为了提高代码的可维护性,是为后来人而写的,但在我看来,代码才是能够决定可维护性的唯一条件,如果开发者的思路清晰,代码又写得优雅而具有条理,那它必然是可维护性好的。反过来,尽管有那些自动化测试案例,但代码却写得非常混乱,这样的程序同样难于维护。完善的测试确实能够有效保证程序的准确性,使得我们每次修改可能造成的错误风险降低,但我们仍然需要优秀的代码来提供良好的可维护性。

  • 测试的方法很多:关于如何测试,我们也不应机械地仅仅去应用那些所谓的自动化测试,在一些较小的,或者需求存在不断变更可能的项目中,我们完全可以用人工测试的方法去快速判断一个功能是否准确,而不是每次需求发生变化,就去重复地写一个测试案例以及一套实现。当需求稳定下来之后,我们还可以完善测试案例,让它们可以在未来被重复执行。总之,根据项目情况和环境,灵活地决定最合适的测试方法。

  • 集成测试越早越好:最后我想说,集成测试必须尽早去做,我看到很多项目中出现的问题,往往是系统间的接口没有尽早约定和测试验证所导致的。双方都错误地认为对方会在接口中提供这样的功能或数据,但最后却发现他们的理解存在偏差,这往往需要极大的代价去修复这些问题。尽早进行集成测试,甚至前期使用一些Mock数据来做验证,能够有效保证系统开发的平稳进行,以及团队间更加顺畅的协作。

那些层出不穷的方法论?

几乎每隔2、3年我们就能看到软件开发领域诞生一套新的方法论,比如在软件架构领域,我们经历了面向模块、面向组件、面向服务(SOA)直到今天我们提出微服务架构。而在开发流程与团队协作领域,我们又经历了从瀑布式和工程化的开发方法到敏捷、XP、Scrum开发,以及今天我们经常挂在嘴边的DEVOPS。每一种新方法论的出现,都会伴随着新一轮大规模的系统改造,同时也会对团队协作方式产生巨大影响。当我们对这些新的潮流趋之若鹜之时,是否也曾想过这些最新流行出现的原因,以及它们是否真的适合你的企业或团队呢?

我曾作为甲方参与由一家知名咨询公司所组建的开发团队,团队的任务是开发一套集团内部的电销核心系统。这个开发团队号称采用了Scrum的管理方式和流程。但我却很快发现,那些所谓的Scrum方法往往只是停留于表面的形式而已,例如,每日的Standup晨会,团队成员们只是例行公事般报一下流水账,而在开发过程中所采用更小的迭代以及每日集成等方法,也由于团队成员技能的参差不齐,而经常导致项目版本的延误,或者因不必要的等待造成的开发效率低下等问题。与之类似,诸如结对编程等在国外流行起来的开发方式,我也几乎从未在国内开发团队中看到成功的实施案例。

那么,我们又应该如何看待这些层出不穷的方法论呢?在我看来,这些所谓方法论都出现在不同的时代大背景之下,又与当时的技术环境紧密相关。比如SOA最流行的时候,恰恰是那些大型企业为了应对内部日益复杂的业务需求而提出的,而作为它的基础设施提供者,像IBM、Weblogic、Oracle等一批中间件服务厂商也在那个时期获得了快速发展。而今天微服务架构以及DEVOPS的出现,则是为了应对如今互联网环境下需求快速变化,以及越来越复杂的运维场景而产生的,它们更是与当前云计算、大数据等领域的飞速发展紧密相关。不难发现,无论是软件架构还是开发协作,这些方法论都在引导着我们向更小、更高效以及更能适应变化的方向发展。对任何企业或团队来说,永远没有什么万能的方法论,你需要根据自己企业所面临的问题和目标,来对这些流行的业界最佳实践进行深入的切割或补充,从而得到对自身最行之有效的实践方法,而不要像赶时髦般去急着应用用那些所谓最新技术或方法。

程序开发领域中还有着很多可以拿来探讨的问题,通过对这些问题的思考,我们发现在软件领域并不存在那些非黑即白的所谓真理或法则。程序开发的美妙之处在于,它是一种深入的脑力活动,充满着令人兴奋的变化和各种抽象思维,我们在一次次选择和解决问题的过程中获得进步。因此,不要被任何思想、教条、方法论束缚住你的思维,只有这样你才能体会到程序开发中的真正乐趣。

评论