首页 > 代码库 > 是什么阻碍了代码的重用?问题是否应该只解决一次即可?

是什么阻碍了代码的重用?问题是否应该只解决一次即可?

原文链接:https://www.zhihu.com/question/21011591

作者:悟网不欢
链接:https://www.zhihu.com/question/21011591/answer/18268958
来源:知乎
著作权归作者所有,转载请联系作者获得授权。

作为曾经对复用问题非常关心的前软件行业从业人员,把知乎的第一答献给这个问题。

我相信许多对复用抱怨的人,可能了误解的复用的含义。而那些强调局限性和折中的人,很可能本身已经拥有良好的复用功底,因此对他们来说,复用的程度更多取决于现实需要。因此这个问题对于开发老手来说或许不值一提,对于新人来说,却绝对重要,它在某种程度上决定了你作为一个程序员所能到达的技术高度。

直截了当的回答,在我看来,阻碍复用的因素只有一个:开发者自己。具体的说是开发者自己的习惯、思维方式和经验。软件设计是一项思维工作,工作的一个重点就是描述流程和划分模块。划分模块的目的,除了逻辑清晰化和便于分工之外,最重要的就是复用。只有把一大堆功能拆分成若干相对独立的小功能,才方便我们把小功能封装起来,随时随地被其它功能(模块)反复使用(调用),这本身就是复用。
从最原始的程序块上升到函数、类乃至设计模式和架构,是对程序功能一步步抽象和灵活描述的过程,也是提高复用性的过程。为什么我们需要架构师?就是因为架构师能够对整个程序,以及程序可能发生的变化做一概括性的描述,在此描述之内,可容纳程序所需的所有具体功能,并可对功能变化表现出适当的容忍性、灵活性和可扩展性。如果不考虑复用,功能稍有变化就要修改或复制大量代码,我们要灵活性和可扩展性有何用?要架构和架构师又有何用?

或许有人会说,我们开发的程序很小,根本不需要架构师,对复用没有那么高的要求,尽快满足客户的要求就好。这个说法的逻辑,如同磨刀一定会误了砍柴功一样,正确,但不合理。我见过泾渭分明的两类程序员,同样从几乎完全没有经验的应届毕业生开始,一类天天忙的喘不过气来,成果却不多。另外一类却越做越轻松,进而经常帮助别人解决问题。除了努力程度之外,是否具有抽象、复用的思维(当然这也可以归结为悟性),是他们在开发能力上的一大分野。
相信大家见过这样的优秀程序员,从一个项目转战到另外一个项目时优秀,从一种语言转战到另外一个语言的时候依然优秀,甚至从一个领域转战到另外一个领域时还是优秀。尽管这种优秀是相对的,但是主要原因在于他能把一个项目、语言、领域的经验复用到另外一个。这是更高层次的复用,而其基础依然来源于软件开发时复用思维的培养与实践经验。

那么,具体来说开发者自己的习惯、思维方式和经验是如何阻碍复用的呢?首先,如果一个开发者在编码之前根本不做任何“程序设计”方面的工作,一接到任务就开始埋头于功能的实现,那么别指望他的代码能有什么复用性,也别指望他能培养起什么复用的思维;其次,如果一个开发者不经常寻找相似模块之间的共性,不打算让自己的模块体现出更强的灵活性,他就没有复用能力,也无法建立复用的思维;最后,如果一个开发者没有足够的经验,他也很难确定复用的边界,很有可能引发过度设计或者放弃复用。
因此,作为开发者,抱怨用户是没有用的,抱怨需求分析师、项目经理或者架构师也是没有用的,交给你的模块在你手中,它的复用性只取决于你,你想让它复用性高一点,那就花点心思去分析和设计。如果你要偷懒,那也随你,只是不要把接口放在别人身上。如果你说你的工作实在太多了,根本没有时间考虑这方面的问题,那我除了对你报以深深的同情之外,只能说一句:同学,身体和职业前途为重。

那么,如何培养开发者的复用思维?就我的经验而言:
首先是严禁复制代码,绝不允许同一个项目或产品的成员复制其它成员(包括自己)的代码直接插入自己的程序,复制已有代码的愿望说明代码上有较大重复,已经构成了复用的条件,在时间允许的情况下,应该要求原开发人对代码进行封装,然后由你来调用。如果时间上来不及,最低限度的折中也是你把这段代码复制过来之后进行分装,然后调用;
其次是对设计过程的强调,新人在开发前,一定要有老手带他进行程序设计和后期的代码审核,这会花费老手的时间,但是回报绝对值得,设计过程培养的不仅仅是新手的复用思维,而是软件开发的基本功,这个基本功与对语言的熟悉程度和项目经验具有同等价值,长期看甚至过之;
最后是适当的交流与指导,实际上,复用问题是新人最容易遇到的第一个显著成长瓶颈,有经验的管理者或者同事很容易发现,在对开发语言和项目逐步熟悉之后,编码成为最不费脑子的工作,而如何避免让自己成为体力劳动者,或者说如何让自己的每一次劳动成果都获得尽量多的后续应用,即复用,开始检验新人的悟性。有悟性的人会自己琢磨、学习、尝试解决,没有悟性的人就开始苦恼。这个时候,就到了指导他们重温面向对象的设计、设计模式等知识的时间了,从这些老生常谈的知识,结合具体的项目实践,所能挖掘出来的复用思维和技术,可能超乎大部分计算机专业毕业生的想象。

事实上,为了解决复用设计问题,我曾经为公司的新人专门开过一门夜校课程,名字就叫“软件复用”。我向他们解释软件复用的极端重要意义,过程很简单,列出了某开源PHP框架对于MVC架构实现的核心代码,解释了短短几行代码所体现的多种设计模式与巨大灵活性。所有人都震惊了,许多人开始意识到编程并不是写代码,更是一种逻辑思维,如果把编程只局限于写代码的水平,那么“码农”的称谓当之无愧。而在这种逻辑思维中,抽象能力是核心,也是复用的基础。
通过大约10多个小时的夜校课程,我很难说显著的提高了他们的水平,但有一点值得欣慰:就是大多数人都接受了“高内聚、低耦合”的思想。众所周知,“高内聚、低耦合”只是模块划分的核心原则,但真正掌握了这个,就基本上迈进了软件复用的门槛,剩下的是实践和提高问题。

上面是从培养的角度来说。对于程序员新人的自我学习,如何提高复用水平,答案也很简单:思考、抽象与重构。首先思考模块划分问题,怎么划分才能尽可能的保证模块的独立性和灵活性,其次寻找相似模块之间的共性,如果找不到,说明抽象程度不够,再往上抽象;最后,舍得花时间重构代码。我完全同意前面大部分人所说的同样代码写到第三遍就会恶心的观点。如果你有时间写三遍,却没有时间重构后,让它被调用两遍,真的很难说到底是偷懒还是过于勤快。

当然复用总是有边界的,开发过程中总会遇到复用所带来的复杂性与时间和代码可读性之间的冲突。这个时候发挥作用的是经验,这个经验既包括复用技术方面的经验,也包括用户需求方面的经验,都需要积累。但是这个冲突不应成为阻碍复用设计的借口,复用首先应该是渗透入程序员血液中的思想,否则前人所作的一切工作,你自己完成的所有任务,理论界、技术界大牛所提供给你的一切工具、模式都是白费。在拥有这个思想,积累的一定的经验之后,你再说:在这个功能点或项目中,复用考虑的不够;或者,在那个功能点或项目中,过多考虑复用并不合适;因为blablabla……

恭喜你,这个时候你已经是一个合格的程序员了。
因为在我看来,复用从来没有该不该的问题,只有够不够和多不多的问题

是什么阻碍了代码的重用?问题是否应该只解决一次即可?