Soft_Job 板


LINE

單元測試有時候反而破壞程式碼的易讀性和維護性 因為要做到單元測試,就得斷開所有的相依性 而對抗相依性,作法就是引入 DI。但是 DI 就會增加代碼閱讀和維護的複雜度。 舉例來說,如果代碼內有時間上的相依性,例如用了 DateTime 物件取得現在時間做某些 判斷,原本可以很簡單的寫出易於閱讀和維護的邏輯: If (DateTime.Now > 12:00:00) then return “PM” else return “AM”; 為了讓單元測試可以控制驗證條件,只能 Interface IDateProvider { virtual GetNow(); } Class DateMock : IDateProvider { GetNow() { return 13:00 } IDateProvider dateProvider = container.Build(....); If (dateProvider.GetNow > 12:00:00) then return “PM” else return “AM”; 然後再搞個 config 想辦法讓程式吃到你寫的 DateMock 類別.... 上面是sudo code 就不用討論語法細節 這就是單元測試的代價!程式真的會比較容易閱讀嗎? 單元測試要花在切除相依性的條件花費的成本時間遠高於撰寫production code 而且你的 production code 能不能賺錢還不知道咧? 到底需不需要單元測試和 clean code ? 先搞清楚寫的用途和目的,你寫的東西有沒有 真正的商業價值再說吧。 不要把 clean code 和 TDD 無限上綱了 工程師最容易自嗨就是這樣,還會自以爲「這是專業」? 乞丐的乞討專業比我們強也不會產生「價值」。 ※ 引述《banqhsia (BEN)》之銘言: : ※ 引述《peanut97 (丁守中)》之銘言: : : 大家中秋節快樂,快收心了。 : : 想問一個假設性問題,大家在工作上,如果有一份專案的 code 是某位前人一手寫的 : : 後來新人加入,變成前人帶新人,此時繼續維護那份code。 : : 但再過一陣子,前人離職了,唯一的創始者走了。 : : 新人把舊 code 重構,或是砍掉重鍊的機率高嗎? : 先跟主管、老闆提,確認有人支持你,不然你會被當成怪物 : 「為什麼要改?」 : 「系統好好的幹麻改?」 : 「改了有好處嗎?」 : 「會花多久時間?」 : 「時間剩不多,要動不動隨便你,不要影響到時程」 : : 我的想像是,如果一份code是出自於1個人之手 : : 我的想像是,如果一份code是出自於1個人之手 : : 那麼code就是他的世界觀、他的切入點 : : 那麼code就是他的世界觀、他的切入點 : : 後面的人看著他的世界觀,有時候不一定能全部接受 : : 而有人的地方就有政治 : : 當他還在的時候,當然就不會亂動。 : : 而當他走了的時候,後面的人,一看不爽,就可能改寫成自己看得爽的、 : : 好改的code。 : : 如果是一個團隊,那當然要好好討論為什麼要改 : : 哪些因素造成現在不好的情況,以及主管同不同意改等等的。 : : 只是我很好奇,1,2人的專案,改的機率高嗎? : : 是不是,code只能是「現在還存在公司的人」能控制的才行。 : 我們公司的經驗,以前因為很多原因 (十幾年前的 code) : 導致系統沒有測試、沒有嚴謹的 coding style、方法註解也很少 : copy paste 是基本,沒有遵照 SOLID : 錯誤不是丟 null 就是 false (欸! 我的 Exception 呢? : 每個 team 成員想怎麼寫就怎麼寫,不管後續的漣漪 : 反正東西交出來就好 多棒 : 然後中間當然成員就是來來去去的 : 我看這之中大概也是 有人進來 -> 看 code -> what the fuck? -> 離職 : 大概就是這種循環 : 因為自己痛過,知道 clean code、設計模式 的重要性 : 進公司沒多久就跟主管說這 code 不能搞,一定要重構 : 每個工程師一定看不爽前人的 code XD : 但是不是說說而已,總是要提出改善的方法 : 理所當然地,你前面那些問題我都被問過 : 幸好我的主管與老闆也是支持我這件事情 : 但是我們討論的結果,現在的 code 也沒辦法全部翻掉,怎麼辦 : 在那個時候剛好要把原本的系統生出一套 API : 原本的系統是 server-side template render,模板與資料、樣式高耦合 : 這個沒辦法改成 API : 我們的作法是,把原本 DAO 抽出來,放進框架裡當成 library : 然後加一層 Adaptor 讓新系統相容舊模組 : 舊的 DAO 邏輯怎樣就不去動他,要改一律在 Adapter 裡面改 : (就算 method rename 也是) : 在這個新系統,以 SOLID 與設計模式為基楚 : controller 與邏輯之間,包裝成 service 呼叫 (一律把該寫的東西放在該去的地方) : service 只准有抽象的敘述,實作的部分寫成介面去依賴,由子類別注入 service : 使用 DI Container 自動注入依賴的類別,不准直接 new (方便替換測試) : 提交功能分支以前,要一併提交單元測試與 functional test,否則不准進 develop : 這些都是規定好寫在專案文件裡面的 (以前沒有的文件,現在開始留下記錄) : 接著就是重頭戲的部分 --- 跟人有關的 : coding style 怎麼統一? 就算統一了還是會有漏網之魚 : 不小心看到 violation 還是會白眼翻到尾椎 : 所以這邊必須用自動化工具檢查,綁在 CI 流程裡 : 這樣已經可以省掉很多人工的部分 : 接著定期 code review,挑出變數不懂、「比較不易修改」的類別… 等等 : 這樣至少做到了幾件事情 : 1. 以前沒有的,現在開始留下記錄 : 2. 把 legacy code 加上 test : 3. 把系統改成 API server 從視圖抽離後,再動前端 (refactor 分階段) : 4. 統一 coding style : 5. 符合 SOLID、易於修改的架構 (為了以後著想) : 當然前面幾篇貼文,有些前輩也有提到 : 「有人的地方就有政治」 : 這句話應該劃 _底線_ 三顆星 ★★★ : 這之中太多阻礙了,電腦不會背叛你,人會 XDD : 做了這麼多品質保證措施,一定會遇到成員反對 : 「一個變數而已,幹麻花這麼久時間討論?」 : 「我覺得 code review 花太多時間」 : 「我覺得一個東西,幹麻拆這麼多類別,放在一個不就好?」 : 深入探討提出這些問題的同事心態,不外乎幾個原因 : 1. 影響 issue solving 時間 --> 覺得產出變慢 : 2. 覺得寫單元測試很麻煩 --> 覺得程式會動就好 : 3. 覺得一個類別不用提煉為抽象+實作 --> 現在又沒這麼多需求 幹麻拆? : 但他們忘記事實是,程式本來就是會修修改改的,而且也是會給別人改的 : 這讓我想到一句話 : 「 : 據統計,你現在挖的坑,有80%會自己來擦屁股 : -- 不知道是誰 」 : 即便跟他們說品質是什麼,clean code 的重要性,他們還是覺得『不需要』 : 所以大多數的問題,都是「人」造成的 : stop writing legacy code,從你我開始 : 但如果你身邊沒人支持,更進一步的說: 沒有得到老闆/主管支持 : 這公司也差不多 GG (因為不在意品質) : 如果你是 team 的其中一個人,試著先從統一 coding style 開始 : 我在 Modern Web 2018 聽到有一場 keynote 是 Terry Yin 大神的「遺留代碼經濟學 」 : 裡面有提到,其實也不用這麼討厭 legacy code : 因為有那些東西,我們工程師才得以被養活。 : 如果你發現有 code 裡面處處是坑,怎麼辦? 那就別再挖坑了啊!! : 我們現在做的,只是把以前沒做的都補回來而已 : 但是,不要再欠下更多的技術債 : 債總有一天還是要還的,而且還會生利息 : 最後我要說一句 : 很多前輩們會建議,要重構前先寫測試 : 但是 : 一個萬能類別/萬能方法/高耦合,要寫單元測試,發現整個系統都要寫 : 有些 hard code 的 class 還不見得可以 mock : 「人」的問題 : 無解。 --



※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 220.135.20.48
※ 文章網址: https://webptt.com/m.aspx?n=bbs/Soft_Job/M.1537962940.A.A36.html
1F:→ Killercat: 這個很正常 要先界定黑箱範圍 這算FAQ了... 09/26 20:10
2F:→ Killercat: 黑箱一開始一定非常大 唯一的要求就是testable output 09/26 20:11
3F:→ Killercat: 慢慢穩定以後才會慢慢的在把黑箱切小 09/26 20:11
4F:→ Killercat: 另外其實你舉的例子怪怪的 這input output都是testable 09/26 20:12
5F:→ Killercat: Mock也沒那麼困難 我不知道為什麼要搞那麼複雜... 09/26 20:13
6F:→ accessdenied: 原本Input不在自己可控的範圍內,早上和晚上測到的o 09/26 20:15
7F:→ accessdenied: utput不同就不能說是testable, 因為單元測試應該要 09/26 20:15
8F:→ accessdenied: 能隨時跑、隨時測、都一致。 09/26 20:15
9F:→ Killercat: er... Mock DataTime.now()很困難嗎 o_oa? 09/26 20:16
10F:→ Killercat: 我知道你想表達的點 但是GMock(C++) Mokito(Java)做到 09/26 20:17
11F:→ Killercat: 這件事情都不困難啊... ? 09/26 20:17
12F:→ landlord: 我不用 interface 也可以模擬 DateTime 耶。 09/26 20:17
13F:→ accessdenied: Anyway, 只是個例子,不用糾結在DateTime 的mock困 09/26 20:18
14F:→ accessdenied: 不困難,實務上絕對會遇到為了Mock而大費周章的案 09/26 20:18
15F:→ accessdenied: 例 09/26 20:18
16F:→ landlord: 你講的是學習單元測試必定會碰到的障礙,這肯定沒錯 09/26 20:18
17F:→ landlord: 但碰到障礙是解決障礙,還是退回原路,就是選擇了 09/26 20:19
18F:→ Killercat: 有是有啦,不過真的不常見,底層才比較會碰到 09/26 20:19
19F:→ senjor: 有,Database的Accessor要MOCK的確蠻麻煩的 09/26 20:19
20F:→ landlord: 任何東西無限上綱跟把它當萬靈丹,都是有問題的 09/26 20:20
21F:→ senjor: 但是回頭來說,程式也是人寫的,既然都知道有特例,幹嘛不 09/26 20:20
22F:→ landlord: 但怎麼拿捏尺度,怎麼往更深入和實務學習,就是專業差異 09/26 20:20
23F:→ Killercat: 我是覺得 碰到mock困難 該做的應該是提出案例討論 而非 09/26 20:20
24F:→ senjor: 針對特例做閃躲就好,何必因為特例否決全部 XDD 09/26 20:20
25F:→ Killercat: 全盤否定掉TDD / UT的concept 09/26 20:20
26F:→ landlord: 為了單元測試而多墊很多不必要的中間層,那是菜鳥錯誤 09/26 20:21
27F:→ Killercat: 應該說 除非語言很奇耙 不然其實現有套件來講 應該很多 09/26 20:21
28F:→ Killercat: 都不需要你墊這些中間層只為了能測... 09/26 20:22
29F:→ Killercat: 或者中間夾了層打不爛的巨大黑箱 不然其實特例討論即可 09/26 20:22
30F:→ landlord: 大部分測試案例難加,難維護,維護成本高,都是設計太爛 09/26 20:23
31F:→ landlord: 而要解決的問題是「設計太爛」,而不是「不寫測試」 09/26 20:24
32F:→ accessdenied: 我沒有要全盤否定喔。但對堅持一定要的人,我覺得是 09/26 20:24
33F:→ accessdenied: 可以多想想的 09/26 20:24
34F:→ Killercat: 我倒覺得思考能不能做到的可能性很重要 不過的確,總會 09/26 20:26
35F:→ Killercat: 碰到一些窒礙難行的時候,我是覺得就討論看看 09/26 20:26
36F:→ Killercat: 說真的以我的經驗 這種case不是很多 09/26 20:27
37F:→ x000032001: 不知道貴公司一天下git blame的次數有沒有上千次 09/26 20:29
38F:→ sharku: Mock技術決定一切 09/26 20:30
39F:→ landlord: 如果模擬now寫成那樣子,我贊成你,我也希望他不要寫。 09/26 20:32
40F:→ landlord: 只是在製造債,把簡單代碼搞得更複雜而已。 09/26 20:32
41F:→ Killercat: 文雅點 我們都叫他annotate而不是blame XD 09/26 20:34
42F:→ accessdenied: 喔!91大週六有課程喔?工程師該去的都去喔,不要再 09/26 20:49
43F:→ accessdenied: 寫拿著那噁心的DI code了 09/26 20:49
44F:→ Killercat: DI都是有原因有目的才DI 不是DI噁心 是亂DI才噁心... 09/26 20:50
45F:→ accessdenied: 也是啦,刀子殺人不是刀子的錯,是用刀的人 09/26 20:52
46F:噓 KanzakiHAria: 大師先推再說 09/26 22:15
47F:→ viper9709: 原來是這樣 09/27 00:45
48F:推 superpai: 你不會寫 pure function嗎? 09/27 09:08
49F:噓 Ghamu: 好棒 09/28 00:34







like.gif 您可能會有興趣的文章
icon.png[問題/行為] 貓晚上進房間會不會有憋尿問題
icon.pngRe: [閒聊] 選了錯誤的女孩成為魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一張
icon.png[心得] EMS高領長版毛衣.墨小樓MC1002
icon.png[分享] 丹龍隔熱紙GE55+33+22
icon.png[問題] 清洗洗衣機
icon.png[尋物] 窗台下的空間
icon.png[閒聊] 双極の女神1 木魔爵
icon.png[售車] 新竹 1997 march 1297cc 白色 四門
icon.png[討論] 能從照片感受到攝影者心情嗎
icon.png[狂賀] 賀賀賀賀 賀!島村卯月!總選舉NO.1
icon.png[難過] 羨慕白皮膚的女生
icon.png閱讀文章
icon.png[黑特]
icon.png[問題] SBK S1安裝於安全帽位置
icon.png[分享] 舊woo100絕版開箱!!
icon.pngRe: [無言] 關於小包衛生紙
icon.png[開箱] E5-2683V3 RX480Strix 快睿C1 簡單測試
icon.png[心得] 蒼の海賊龍 地獄 執行者16PT
icon.png[售車] 1999年Virage iO 1.8EXi
icon.png[心得] 挑戰33 LV10 獅子座pt solo
icon.png[閒聊] 手把手教你不被桶之新手主購教學
icon.png[分享] Civic Type R 量產版官方照無預警流出
icon.png[售車] Golf 4 2.0 銀色 自排
icon.png[出售] Graco提籃汽座(有底座)2000元誠可議
icon.png[問題] 請問補牙材質掉了還能再補嗎?(台中半年內
icon.png[問題] 44th 單曲 生寫竟然都給重複的啊啊!
icon.png[心得] 華南紅卡/icash 核卡
icon.png[問題] 拔牙矯正這樣正常嗎
icon.png[贈送] 老莫高業 初業 102年版
icon.png[情報] 三大行動支付 本季掀戰火
icon.png[寶寶] 博客來Amos水蠟筆5/1特價五折
icon.pngRe: [心得] 新鮮人一些面試分享
icon.png[心得] 蒼の海賊龍 地獄 麒麟25PT
icon.pngRe: [閒聊] (君の名は。雷慎入) 君名二創漫畫翻譯
icon.pngRe: [閒聊] OGN中場影片:失蹤人口局 (英文字幕)
icon.png[問題] 台灣大哥大4G訊號差
icon.png[出售] [全國]全新千尋侘草LED燈, 水草

請輸入看板名稱,例如:Tech_Job 或 站內搜尋

TOP