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/cn.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