zoukankan      html  css  js  c++  java
  • 10种软件开发中 over-engineering 的错误套路

    别把「不要过度使用 Generic」误解成「不用 Generic」。也别把「不要写一些不必要的 Wrapper」误解成「不写不论什么 Wrapper」。我仅仅是在讲 over-engineering 这个事。仅仅是在提倡不搞野路子编程。


    套路1:攻城狮自觉得比业务人员聪明

    攻城狮认为自己最聪明,由于东西是他们写出来的嘛!

    然而这常常就是 over-engineering 的根源。

    即使我们考虑好100件事情。还是会有第101件我们没想到的事情冒出来。

    就算我们搞定了1000个问题,还是会带出10000个新问题。我们认为一切尽在掌握,可是事实是要打脸的。

    在我15年的 coding 生涯里,我还从来没见着哪块业务光用需求就能概括清楚了。业务总是会变得五花八门。这不是业务人员的错,这是业务的天性使然。

    长话短说:别和业务争。他们是赢定了的

    温馨提示:假设你时间不多。这篇文章 Get 到上面这点就够了

    套路2:过度复用业务逻辑

    业务需求越来越多时(早就料到有这么一天),我们的反应是:

    我们挖空心思搞抽象,搞复用,结果搞出一堆 Fat Models Fat Controllers。

    然并卵,业务需求从来不知足,仅仅会越来越复杂,这个套路 hold 不住。 
    所以。应该反其道而行之:

    在合理的系统中。共享逻辑会随着时间沉淀下来。即使外部功能变多,也依旧保持「身材」。

    假设你看到的情况与此相反,恭喜你,你手上的系统早晚难逃被所有重写的命运。由于实在难以做局部的改进了。

     
    在水平划分业务之前。最好先考虑垂直划分。比方不相干的服务,流程相关的逻辑,语言相关的模块。等等。这样一来改个局部的地方就比較easy,不用想太多。

    长话短说:不要搞组合共享,要隔离

    温馨提示:去代码库里挑一个和外部系统(Endpoint/Page/Job/etc)打交到的 Action 来看看,算一算这段代码的运行过程中须要切换多少个 Context?

    套路3:不论什么东西都要 Generic

    (本套路有时候是与套路2一起发作的。有时也单独发作)

    • 连接数据库?写一个 Generic Adapter
    • 查询数据库?Generic Query
    • 传參数?Generic Params
    • 构建參数?Generic Builders
    • Map the Response?Generic Data Mapper
    • 处理用户请求?Generic Request
    • 干全部的杂活?Generic Executor
    • 等等等等

    有时候攻城狮就是管不住自己的欲望:不先去解决详细的业务问题。而是要浪费时间搞一个完美的抽象。 
    设计仅仅能是追着真实生活的需求跑,所以哪天即时我们吃了狗屎运搞出个完美的设计。完毕的时间也就是过期的时间——业务变了。最吼的设计就是易于重构的设计。

    这篇文章提倡的是大家应该写删了不心疼的代码,而不是老是想着被扩展的代码

    长话短说:错误的抽象比反复还要糟糕

    假设要做合理的抽象,适度的反复是必须的,由于仅仅有我们从足够多的反复中总结的抽象才是好抽象(别一開始没多少反复就着急搞抽象)。抽象的质量。往往是系统里最薄弱的一环。

     
    正经提示:在微服务之间搞抽象简直是灾难,会导致分布式巨无霸怪胎产生

    套路4:影子封装器(Wrapper)

    曾经用到外部库时,总要包装包装,但往往仅仅是影子封装法。我们也就仅仅在实现功能和打包第三方库之间玩玩小把戏。

    所以呢,我们所谓的封装事实上是和底层实现绑得死死的(有时候仅仅是1:1的搬功能,有时候甚至花10倍功夫来包装,而仅仅实现了底层库1/10的功能)。假设以后我们把底层库换了,包装器就得跟着改。有时候还在包装器里带点业务逻辑,搞成个四不像,最后成了个懵逼胶水层。

     
    如今是2016年了,醒一醒吧!第三方库都已经做得又快又好了。写这些库的人都非常聪明:质量好、測试好、有钱有闲写得好。用这些库的时候。就仅仅管依照 Initialize-Instrument-Implement 的模式来用即可了。

    长话短说:写 Wrapper 属于意外事件,不要当作常态。不要为了包装而包装

    温馨提示:不是开玩笑。有人就是想搞能「海纳百川」的 Wrapper,理由就是,能够随时更换实现库啊!这是一种病,參照后文中的「可X性」套路

    套路5:用工具思维对待质量问题

    盲目地套用代码质量概念。并不能实际提高代码质量。比方:把全部变量都写成 private final。给全部的服务类都加一个 interface,等等。

     
    看下 Hello World 企业版 或者 FizzBuzz企业版 ,代码写得巨多,且搞笑。

    细看每一个类都严格遵守实现准则了,设计模式也用得蛮多(工厂,构建器,策略,等等),编码技巧上也下了苦功夫(泛型,枚举等等)。拿工具一检測,代码质量给满分。 
    可是,从大处一看。这货也就打印一句废话。

    长话短说:别迷恋细节,要从大局出发

    自己主动化代码质量检測工具能帮我们盯覆盖率这些东西,可是分辨不出測试是不是測了须要測的东西。

    性能检測工具能測性能。也不知道程序是并行还是串行跑出来的。仅仅有人才把握得了大局。 
    否则。就会催生出千层饼现象:把代码逻辑切割到10到20层面饼里面,但每一层对全局的了解都是懵逼状态。

    为什么会酱纸?就是由于我们单纯追求代码可測试性,或者单一职责原则这些东西,忽视了大局观。

     
    在曾经。大家喜欢搞继承。A继承B继承C继承D等等。

    在如今。大家还是喜欢搞这一套,仅仅只是加上了配套的接口和实现。

    每一层都有接口和实现去调下一层,由于这非常规范嘛。

    有一些非常好的原则。就是用来对付继承和其它OOP滥用的现象的。非常多攻城狮不知道这些原则的来源。仅仅管照本宣科。是有问题的。

    长话短说:同样的概念在不同的领域有不同的含义。不要见得风就是雨。拿着锤子眼里仅仅有钉子

    在别的领域。要学会说人话。好的开发人员要靠这个混。新瓶装老酒是行不通的。永远不要以套用概念的名义把设计搞乱。

    套路6:Adopter 狂热症

    无处不在的泛型。

    这个世道上。HelloWorldPrinter 都要写成 HelloWorldPrinter< String, Writer >

    假设问题明显能用普通的方法、专门的数据类型来解决。就不要乱搞泛型。

    无处不在的策略模式。

    连 if 都想用策略模式来做。

    脑子有毛病?

    无处不在的 DSL。想用 DSL重写全部东西。

    不知所云……

    喜欢用 Mock。測试时不论什么东西都想 mock 一下。

    假设玩砸了……

    元编程好屌,什么地方都搞一搞。

    能讲讲理由么!

    枚举好屌,扩展方法好屌,Traits好屌,好屌好屌。用起来!

    骚年,这是不正确的!

    长话短说:不要什么地方都长话短说

    套路7:痴迷「可…性」

    • 可配置性
    • 可伸缩性
    • 可维护性
    • 可扩展性
    • ……

    瞎搞。不可理喻。

    顽冥不化。

    栗子1:来做个可扩展性屌屌的 CMS 吧!

    业务人员能够随心所欲地给实体加字段。

     
    结果:业务人员从来不用。假设非用不可,他们会抓一个码农来帮他们用。本来就想要几个经常使用字段。快点出结果。结果你给我搞一个狂拽酷炫然并卵的界面出来。

    栗子2:设计一个可配置性极好的数据库。

    改个文件就能自由切换底层数据库哦! 
    结果:10年以后。我仅仅见过1家公司动真格去换底层数据库。到了真换的时候,那种所谓的配置隔离文件起不了什么作用。有太多运维工作要做了,不兼容性、功能不匹配,等等。等到我们的客户要求我们光换个配置文件就把半数表格换到 NoSQL 去,我们就疯了:配置文件仅仅是千千万万要修改的地方之中的一个,客户你玩儿我呢? 
    今天根本没有办法光凭一个配置层就能把传统数据库和新的 文档/KV 数据库(Redis CouchDB DynamoDB)统一起来。甚至不同的传统关系数据库之间也不行(MySQL Postgres SQLite)(这一段我不想翻译了,我认为这个是个常识)

    长话短说:不要对「可…性」的痴迷坐视无论。要清晰地定义问题场景/用例/需求/解法

    套路8:不务正业的 「玩具小发明」

    从头開始做东西总是让人感觉良好。可是这些东西非常快就没人用了。

    几个栗子:

    • 玩具程序库(HTTP,迷你 ORM/ODM,缓存,配置,等等)
    • 玩具框架(CMS,事件流,并发。后台任务,等等)
    • 玩具工具(构建、部署工具,等等)

    不要忘了:

    • 熟悉问题域不是一件轻松的事。要花大量的精力和技巧。

      一个成功的 Service Runner 库是建立在对 daemon work、进程管理和I/O等等的专业知识深入了解的基础上的。一个 CMS 也不是显示几个字段那么简单,这些字段有内在的联系,还要校验、向导、适配显示等问题要解决。

      一个看起来非常easy、就仅仅做 「重试」这么一件事的程序库,其实也不是那么easy做好的。

    • 维护这些个玩具库须要持续花费时间和精力。再小的开源库要维持运转也是一个easy的事情。
    • 就算把这些东西开源了,除了你自己和那些要靠它们吃饭的人。不会再有别人去看的。

    • 那帮人开源了这些东西,心惬意足地在简历里写上「XXX创始人」之后。一般就会慢慢撒手无论了。

    • 维护当前的东西须要在当下花时间。可是创造新东西是在透支未来的时间。(译者注:向未来的人借时间债)

    长话短说:复用已有的!复制优秀的!

    学会贡献!学会三思!

    最后,假设真要不得不去做一些超前的事。要带着创业心态去做。要和现有的同行竞争。要争取内部同事的信任和支持。不要认为都是自己人就无所作为,把一切看作理所当然了。

    套路9:安于现状

    假设有些东西一開始以某种方式去实现了。那么全部人会默认依照这样的思路接着做下去。

    没有人会去质疑一下原因。能干活的代码就是「好代码」。即使实现的过程有些迫不得已,大家也会绕着弯去适应现状。

    一个健康的系统应该是持续演进的。不健康的系统特色就是一直在修修补补。假设一块代码非常久都没人提交了,说明这块代码已经開始变臭了。

    系统的每一部分都要与时俱进。

    这篇文章写得非常好:不要把重构任务一直放在 backlog 里!

    一个团队每天实际迭代的状况。和他们理想中的迭代方式对照:

    长话短说:重构是每天日常工作的一部分。没有什么代码是不能改的。

    套路10:胡乱预计

    真心的,常常会见到素养还不错的攻城狮/团队却写出了一坨屎。

    看到他们写的代码,我们会想。卧槽。这真是那个号称非常牛逼的人做出来的么?!

    质量不光靠技巧,还要靠时间来凑。

    越聪明人的人,越easy自信满满导致预计失控。

    (WTF?)最后呢。仅仅好靠一堆 hack 技巧和自杀性工作时长来把事情了结。

    长话短说:还没写代码之前,错误的预计就能毁了project质量

    假设你能耐心看到这里,我谨在此表示由衷的感谢!还是别忘了,我仅仅是在讲 over-engineering 这个事,仅仅是在提倡不搞野路子编程。


  • 相关阅读:
    内核配置中Default kernel command string和uboot中bootargs变量的区别
    内核编译配置选项含义
    WARNING: Unable to open an initial console
    Linux内核学习之四库全书
    EABI和OABI
    0.8.11版本ffmpeg一天移植将近完成。
    mmsplayer for wince,windows demo已经发布
    mmsplayer for wince,windows demo已经发布
    0.8.11版本ffmpeg一天移植将近完成。
    ffmpeg AT&T汇编转intel汇编 之(read_time)
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/8455547.html
Copyright © 2011-2022 走看看