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