Re: [讨论] Clean Code vs Efficiency

楼主: CoNsTaR ((const *))   2016-05-28 02:27:03
其实这要看你的抽象化程度
一般在阅读程式的时候除非有必要,否则都不会追究到程式架构的最底端
我们都会在抽象化程度偏高的地方浏览,真的有需要才会再往下一层去检视实作
如果你的程式会让阅读者想要看里面的实作通常代表
1. 你的设计没办法交代清楚它到底确切在做什么?需要什么?使用时机?使用限制?…

一些惯例(命名惯例,design patterns…)可以让阅读者一眼就取得这些隐含的资讯
2. 这个东西的功能太神奇了(程式行为超出预期),超出一般人的预期
像是 qt 的 signal slot 机制就会让第一次接触的人摸不著头脑
因为它用名称来配对 signal slot 的做法不是标准的 c++ 语言可以做到的
3. 底层程式有虫,要抓虫啦
4. 你的 code 很漂亮,很能够引人入胜,让人家很想一直继续往下看 XD
所以说,要是有一个好的设计
那么阅读者根本就不需要去看那些效率取向的,最佳化过后的难懂的实作
因为你的设计就已经提供给阅读者他想要的所有资讯
根本不需要自己去阅读实作慢慢推敲啊
以上是对于提升整个系统整体的可读性,如果是要考虑实作本身的可读性的话
那么重点就会放在职责的切割和分配
最快最有效率的检查方式就是看在同一个 block 内的 code 的抽象化程度是否差不多
要是上一行是系统顶层的操作,下一行又是底层的东西,看起来一定很痛苦吧
而且这样把两个不同阶层的东西绑在一起就是在制造多余的相依性
回到原 po 算法取舍的问题,我会推 policy based design
它不但保留了程式的扩充性,又不损失效能,超美的 XD
※ 引述《gitignore (git)》之铭言:
: 最近上班在思考这问题
: 假如今天有个 O(log n) 的方法可以写出一个东西
: 但是程式码无法简化 以后维护的人应该也会很痛苦
: 因为不直观
: 另一个就是程式码非常简洁 但就一定是O(n) 甚至 O(n^2)
: 不知道大家会倾向于哪种?
: 我个人是比较喜欢clean code 因为过一阵字自己回来维护也比较快上手
: 但是感觉在学校学这么多 就是要能写出效率较好的程式码
作者: wesley234 (扫地)   2016-05-28 08:07:00
观念正确,脑袋清楚除非人家想要改Code,否则对于一个呼叫者来说根本懒得看细节人与人之间是合作整合的关系,各自负责不同的部分不是都做一样的事,然后相互比较看谁强,这跟学校不同Code太脏,苦的是接手的人,或者是未来的自己
作者: comesuck (艾米德)   2016-05-28 10:48:00
不是每个人的心态都这么健康的...听不懂抽象化是什么的比想像中的多...
作者: GoalBased (Artificail Intelligence)   2016-05-28 11:29:00
听不懂又整天挂在嘴上讲的可怕
作者: abc0922001 (中士abc)   2016-05-28 13:25:00
看别人的Code,起手势不是“写这么烂都看不懂”
作者: sunsamy   2016-05-28 20:44:00
请问policy based design的overloading的Template泛型最终runtime实现方式也是一堆case或if else在那比对?这样效率会好吗?不晓得我认知有没有错?
作者: kiwatami (悠游自在)   2016-05-28 21:41:00
可是瑞凡 在接维护的人难免都会需要改程式这个时候就需要看程式码你这篇的角度比较像是 api 使用者其实有时候只是老板希望产生的结果从 a 改成 b而这个算法刚好是产生结果的核心部分这样不管怎么抽离都会需要改程式码所以程式的可读性与文件才会这么重要这也是为什么我觉得你的说法比较接近 api 使用者
作者: comesuck (艾米德)   2016-05-29 10:29:00
kiwatami 你指的应该是BO(or DAL)使用者吧只要当初写code的人体质很差,很容易就会维护到这种三四个功能都挤到一个function里做但这些问题会一直累积到要改“机制”or“规则”的那个人身上不用在意业界生态如何,用对的方式写code就好不要被“实务上”魔人牵着走;因为我认为“因为我不懂,所以不这样做”不等于“实务上”情境大致上是这样:“为什么不画Uml?”、“为什么不用delegate?”、“为什么function一次做五件事?”答案开头都会是“实务上没人这样做...”最后一个问题改成“为什么function做五件事不拆出来?”
作者: kiwatami (悠游自在)   2016-05-29 11:10:00
我指的 api 使用者其实就是一般开发者通常不需要管原始码 只要负责呼叫 method 就好这样才符合原 po 提到的 1234点接维护的人不太可能不需要读原始码差别在于读的范围多寡而已其实就算只有一个功能 复杂的算法阅读起来也很花时间如果改动幅度很大或是牵扯到资料来源内容的变更这样想不读都不行 因为要评估重写的可行性以及是不是有把握重写后的效能可以接近或是超过原本的在这种情况下不论原本的架构有多好 都需要去读原始码
作者: comesuck (艾米德)   2016-05-29 12:19:00
原po针对的是算法的部分;架构切割不完全(没有各自负责功能的class or method)只要开发者开始负责某功能,而资料存取不是透过外部(ex:http api)取得,那所有这个功能相关的算法、资料存取 source code他都必须trace 一遍至于算法复不复杂,算其次;这个算法符不符合需求domain的情境,才是维护的人该注意的跟需求落差很大的source code,对使用者来讲毫无用处甚至会误导方向
作者: kiwatami (悠游自在)   2016-05-29 22:22:00
接维护通常是验收后的程式了怎么会有跟需求落差很大这种东西...?原po第一段提到为什么要阅读 但接维护没有为什么要改功能就是要读 要修 bug 就是要读所以才说原 po 是从一般使用者的角度 才有所谓要不要读第二段其实有点偏离主题 因为通通写在一起不会跑比较快同理功能分离效能也差不了几微秒所以效能问题不太会牵扯到这个东西这反而是开发速度与维护速度的问题而 原原 po 要探讨的就是高效能复杂的算法以及普通效能但可读性高的算法该如何选择也就是未来的可维护性 怎么复杂度反而变成其次考量呢?是瓶颈的不管多复杂都要用 但解法不一定只有一种这反而是写程式最花时间的时候 选择使用哪一种方法解以及评估各方法间的效能差异为了解决问题 就算接手的人要花一个月才看得懂也得硬著头皮写下去 注解超多行 文件超厚也得写反之就尽量维持高可读性 因为不是重点其实 原 po 说的并没有什么不对的地方只是出发点跟原原 po 要探讨的有点不同而已
作者: comesuck (艾米德)   2016-05-29 23:17:00
可能最后有点扯远了XD,但“验收过”不等于“功能符合需求”(起码要有9成才算);但经验遇过的很多都是功能“部分符合”(5成),验收先过,之后再补。至于功能通通写在一起,影响最大的不会是效能;影响最大的会是可读性与可扩充性;class功能职责区分不明确,新功能程式码找不到地方摆,就必须先重构对,原po一开始确实针对原原po的问题回应(开发);只是后来的推文、编辑回文,情境转成维护;是两个讨论主题
作者: ripple0129 (perry tsai)   2016-05-30 08:36:00
差不多是这样,一开始就看原始码我也觉得不如ㄧ开始先写测试程式,结果都如预期事实上原始码可以跳过。一些pattern的用意也是让你可以不用管底层实作
作者: kiwatami (悠游自在)   2016-05-30 10:26:00
验收过待补不会交维护 而且那也是整体功能有缺怎么可能有算法跟需求落差很大这种事?那写这个算法出来是练打字吗?算法他就是一个完整的功能他不会只有一个 method 也不会有什么架构问题也不需要考虑接口什么的执行绪可能也不只一条纯粹就是为了解决问题所以逻辑上比较复杂这种算法怎么可能说重写就重写要修改的部分也可能是其中的好几个地方而在这样的过程中完全不用读程式码?还是说只有读到int a = b; 才算"读"程式码?你说的比较像是各功能间配合的"开发模式"说到后来反而像是在教人写程式该怎么写才漂亮不太像是原原 po 主要探讨的议题就像我们在讨论烤鸡翅要这样调烤肉酱才好吃你却在说烤肉架最好用精工牌的 a5 型号烤起来最好吃虽然最后都会影响到好吃程度可是酱料该怎么调 跟烤肉架用哪牌是两个不同的层级不是说你推荐的烤肉架不好用 而是酱料才是灵魂啊!
作者: comesuck (艾米德)   2016-05-30 12:56:00
认为算法跟需求落差很大是罕事,我没意见;只是在一个常态使用合约里空泛的几句话去定义一个功能scope的大环境底下,出现算法与需求的落差,机率应该颇大吧?对,假设原原po的情境是:a要调出好吃的烤肉酱把烤肉烤好;那原po的情境比较像是:烤肉的任务a进行到一半,烤肉酱的材料切好了,现在换成b来接手,b凭经验把材料组好变成烤肉酱,再完成烤肉任务。期间,只要换口味了,那就会发生酱料不符合口味的情境。至于不同厂牌的烤肉架,比较像是决定实作的framework或语言掌厨的人跟酱料会是胜负的关键我在讲什么...咦?XD
作者: GoalBased (Artificail Intelligence)   2016-05-30 18:56:00
假设情境是,bubble sort比quick sort容易读,但quicksort比bubble sort还快,那要选哪个呢?原PO的问题比较像是这样吧...
作者: ripple0129 (perry tsai)   2016-05-31 02:01:00
会用quick sort然后做成api出来是要的结果就好了,里面的东西不用读了,知道怎么用即可XD。我是觉得楼主说的很清楚了,大概就类似这样的做法。除非是算法出问题不得不进来读原始码吧。
作者: kiwatami (悠游自在)   2016-05-31 10:21:00
算法跟需求落差很大验收还会过那我干脆写个假结果给他验收就好啦...何必写什么复杂的运算结果还是错的不是效能瓶颈的地方当然不需要用复杂算法因为提升的效能很有限再来不管你分割的多清楚 你就是得读原始码难道原本只需要改循环的数量就好也要重写吗?没有读过怎么会知道要改循环的数量呢?难道名称是 loop3times 吗?不然只看名称怎么知道?知道怎么用不需要读里面的就是一般使用者的情境维护人员一定需要读里面的东西难道你读程式码的定义是我没有读完全部就不算读吗?我只读了三分之一 只读了其中的几个 method 就不算读?再提一个更简单的例子假设今天某个变量在运算过程中要多加一个常数难道你事先知道这边要这样改吗?还是说每个计算不管多简单 就算只是指定变量值也要切出来?为了所谓的预防万一以后要改?难道不可能会有以上这种情况发生?维护要改的东西什么都有可能什么都不奇怪更何况有些时候算法是要一直调整的还是说在你的理论里不会有开发到一半离职的情形?还是说接手的不管如何就是重写尚未完成的部分?如果不是的话你要怎么知道他写到什么程度?靠名称?靠惯例?靠心电感应?(喵喵)用一个开发模式就号称以后完全不需要动原始码这不太可能 不管你切的多细多完美影响到的只有读的范围多寡而已 而不是"不用读"原 po 假设的情况太过于完美 而现实的瑕疵太多了是瓶颈的部分不管你算法多复杂都要写这我应该提到几次了 简单的算法也不是只有初学者的语法而是不用过于特殊的方法去解决问题可读性的意义跟简单完全是两回事 风马牛不相及
作者: comesuck (艾米德)   2016-05-31 12:10:00
会有这种结果,就不懂软工啊;使用者只看ui;与修改中的功能相关的class,只要用到的method都要读(只用到两个,你没必要把20个全看完,但看懂是其次,意不意会的到它有没有符合情境才是关键);今天不会莫名其妙加常数,决定加一定是因为有需求、有情境、经过讨论后才决定修改抽象化与实作;ok,程式码开发到一半人员离职怎么办?看你如何降低程式码与开发者的耦合,对我来讲,就是画UML把抽象化概念拉出来讨论(画到sequence diagram 就可以收敛大部份的方向了);开发者按图施工,就算你写到一半闪了,也不会出现不知道抽象化怎么做下去的窘境;切function爱怎么切看开发者,好或坏由维护的人定夺;但记得禀持童子军的精神做认为是对的事就对了~
作者: viper9709 (阿达)   2016-05-31 23:57:00
推这篇~观念正确
作者: kiwatami (悠游自在)   2016-06-01 10:10:00
我从来不认为你说的是屁 一直都很赞同你说的也没有说不要用你的方法去实作只是你的角度与原原 po 要讨论的不同啊...你说这样的写法不需要读 所以我回应你说不可能不用读你说这样的写法不需要改 只要重写但很多时候不可能重写就好所以举例了一堆情况为什么有算法需要调整?因为这个算法可能是顾问提供的算出结果后发现有偏差于是需要调整因为这一大堆情况都需要"读" "改" 程式码而你一再强调不需要读 也只需要重写我反驳的从头到尾都是这点 但你最后的回应搞得好像我反驳的是你提倡的开发模式也似乎忘了你一开始一直坚持的不用改不用读甚至连注解跟文件都不用写不是吗?从头到尾你观念错误的地方从来就不是开发模式而是你把接手人员的情况想得过于简单把这个开发模式想得过于强大好像用了这个开发模式一切都不会有问题我反驳的是这个过于天真的想法把我打成一个异教徒并没办法掩盖这个事实为什么讨论到后来总是变成在酸人 乱扣帽子最后连自己当初坚持的想法都忘记了?要不要回头看看你说的东西 再看看你最后的回复?完全像是两个不同立场的人在说话最后那段酸文对讨论又有什么帮助?
作者: comesuck (艾米德)   2016-06-01 12:47:00
他提倡较好读较好改...没有到不用读不用改吧
作者: kiwatami (悠游自在)   2016-06-02 09:34:00
原 po 第一段提到"程式为什么让人想看里面的实作"没有为什么 要改就是要看 这4点只符合一般使用者并不符合一般接手程式的情况但之后原 po 又说其实要读 只是范围小了点这不是完全跟你前面几次回复要说的完全不同了吗?之后原 po 又提到"要是算法不合需求了 重写就好""也不需要看程式内的实作""要表达程式资讯最棒的方法是使用惯例""因为注解文件又累又丑"并不是炮你表达 而是以上这些观念都是不对的原原 po 的问题不成立是因为该写的地方不用考虑复杂度而不是你说的"只要架构够好根本不需要读"这不是表达的问题 这是你真的这样认为才会这样说因为你觉得这个开发模式太美妙 想推广给大家但不得不承认的是很多情况并不是开发模式可以解决的但你又坚持可以 只是对方贯彻的不够彻底你最后也说很多结论有适用与不适用的地方但我提出了不适用的地方 你却一直反驳这其实适用无法接受这个事实的不就是你自己吗?不是体质不够好 就算体质再好你还是要读这这是我一直想告诉你的 但你一直不接受最后你的回复不就是我前面一直想说的吗?但你又把我打成了你的方法无用论者明眼人都看得出来很聪明那段是在酸人写 code 架构差又死脑筋不愿改进我只是觉得这对讨论一点帮助也没有这不是夸张了点 这是夸大成效 你要做的不是描述各种眉角而是忠实传述这个开发模式的优点与目的就好不用读 不用改 不用注解与文件云云根本是多余又错误的可以的话请你回头看看我在14楼回你什么是不是就是你说的某些不适用的情况?但结果呢?你不接受 才有了这一大篇最后都歪楼的讨论但最后你又接受了... 却又说我在钻牛角尖但我要表达的就是你最后结论提到的有适用与不适用的情况 这点而已也是你一开始坚持绝对没有的东西
楼主: CoNsTaR ((const *))   2016-06-02 22:12:00
嗯…很好啊 战斗力满分 继续保持……

Links booklink

Contact Us: admin [ a t ] ucptt.com