Re: [讨论] 前人的code 后人翻写的机率高吗?

楼主: accessdenied (存取违规)   2018-09-26 19:55:39
单元测试有时候反而破坏程式码的易读性和维护性
因为要做到单元测试,就得断开所有的相依性
而对抗相依性,作法就是引入 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
: 这些都是规定好写在专案文件里面的 (以前没有的文件,现在开始留下记录)
: 接着就是重头戏的部分
作者: Killercat (杀人猫™)   2018-09-26 20:10:00
这个很正常 要先界定黑箱范围 这算FAQ了...黑箱一开始一定非常大 唯一的要求就是testable output慢慢稳定以后才会慢慢的在把黑箱切小另外其实你举的例子怪怪的 这input output都是testableMock也没那么困难 我不知道为什么要搞那么复杂...
楼主: accessdenied (存取违规)   2018-09-26 20:15:00
原本Input不在自己可控的范围内,早上和晚上测到的output不同就不能说是testable, 因为单元测试应该要能随时跑、随时测、都一致。
作者: Killercat (杀人猫™)   2018-09-26 20:16:00
er... Mock DataTime.now()很困难吗 o_oa?我知道你想表达的点 但是GMock(C++) Mokito(Java)做到这件事情都不困难啊... ?
作者: landlord (91)   2018-09-26 20:17:00
我不用 interface 也可以模拟 DateTime 耶。
楼主: accessdenied (存取违规)   2018-09-26 20:18:00
Anyway, 只是个例子,不用纠结在DateTime 的mock困不困难,实务上绝对会遇到为了Mock而大费周章的案例
作者: landlord (91)   2018-09-26 20:18:00
你讲的是学习单元测试必定会碰到的障碍,这肯定没错但碰到障碍是解决障碍,还是退回原路,就是选择了
作者: Killercat (杀人猫™)   2018-09-26 20:19:00
有是有啦,不过真的不常见,底层才比较会碰到
作者: senjor (哞哞)   2018-09-26 20:19:00
有,Database的Accessor要MOCK的确蛮麻烦的
作者: landlord (91)   2018-09-26 20:20:00
任何东西无限上纲跟把它当万灵丹,都是有问题的
作者: senjor (哞哞)   2018-09-26 20:20:00
但是回头来说,程式也是人写的,既然都知道有特例,干嘛不
作者: Killercat (杀人猫™)   2018-09-26 20:20:00
我是觉得 碰到mock困难 该做的应该是提出案例讨论 而非
作者: landlord (91)   2018-09-26 20:21:00
为了单元测试而多垫很多不必要的中间层,那是菜鸟错误
作者: Killercat (杀人猫™)   2018-09-26 20:21:00
应该说 除非语言很奇耙 不然其实现有套件来讲 应该很多都不需要你垫这些中间层只为了能测...或者中间夹了层打不烂的巨大黑箱 不然其实特例讨论即可
作者: landlord (91)   2018-09-26 20:23:00
大部分测试案例难加,难维护,维护成本高,都是设计太烂而要解决的问题是“设计太烂”,而不是“不写测试”
楼主: accessdenied (存取违规)   2018-09-26 20:24:00
我没有要全盘否定喔。但对坚持一定要的人,我觉得是可以多想想的
作者: Killercat (杀人猫™)   2018-09-26 20:26:00
我倒觉得思考能不能做到的可能性很重要 不过的确,总会碰到一些窒碍难行的时候,我是觉得就讨论看看说真的以我的经验 这种case不是很多
作者: x000032001 (版废了该走了)   2018-09-26 20:29:00
不知道贵公司一天下git blame的次数有没有上千次
作者: sharku (明珠求瑕)   2018-09-26 20:30:00
Mock技术决定一切
作者: landlord (91)   2018-09-26 20:32:00
如果模拟now写成那样子,我赞成你,我也希望他不要写。只是在制造债,把简单代码搞得更复杂而已。
作者: Killercat (杀人猫™)   2018-09-26 20:34:00
文雅点 我们都叫他annotate而不是blame XD
楼主: accessdenied (存取违规)   2018-09-26 20:49:00
喔!91大周六有课程喔?工程师该去的都去喔,不要再写拿着那恶心的DI code了
作者: Killercat (杀人猫™)   2018-09-26 20:50:00
DI都是有原因有目的才DI 不是DI恶心 是乱DI才恶心...
楼主: accessdenied (存取违规)   2018-09-26 20:52:00
也是啦,刀子杀人不是刀子的错,是用刀的人
作者: KanzakiHAria (神崎・H・アリア)   2018-09-26 22:15:00
大师先推再说
作者: viper9709 (阿达)   2018-09-27 00:45:00
原来是这样
作者: superpai (超级白)   2018-09-27 09:08:00
你不会写 pure function吗?
作者: Ghamu (猫丸)   2018-09-28 00:34:00
好棒

Links booklink

Contact Us: admin [ a t ] ucptt.com