缘起

上周修改一个Bug,本来以为只需要做一些小调整就可以,后来还是发现由于受对象间的状态影响,出现了另一个错误。这也让我进一步思考对于系统设计和建模来说:面向对象是错误的,会带来后期的很多问题。

面向对象

在面向对象的设计中,系统是由对象和让对象状态发生改变的方法,让对象到达另一种状态来达到目的的。当系统渐渐变大,对象渐渐变多,每个对象间的纠缠越来越多的时候一个对象的状态受到多个控制信号的机会就越来越多,作为状态的使用者,你越来越无法判断你所用对象的状态——时常由于外部改动让状态发生的改变,你的编程假设也就失败。这通常会造成Bug的产生,而且很难定位和修复这样的Bug。

从代码的观点来说,操作对象的代码和对象结合的太紧密,你复用的机会会越来越少,对象上的方法是针对这个对象的特化方法,你很难加以利用。所谓的高内聚让你对于已有的方法只能看,而不能用,相信对于维护代码的同学特别有这样的感觉:你的需求基本上另一个对象已经满足了80%的功能,或者你想剥离其中某个方法,会发现根本没有办法拨出来,这个方法跟对象紧密的结合在了一起。

对于维护调试来说,你会发现当系统出现问题时候,你很难改变对象上的方法,很多时候看似有问题的方法对于这个特定的对象来说居然是正确的,前提是有很多Setup让对象处理这样的状态。在调试的时候好像一些几何相关的谜题,你移动了一个角度,以为这样就能通过,其实移动带来的副作用让你无法通过。

函数式架构

系统的设计还是要采用函数式的结构,把系统看做一个数据转换器(transform),而不是状态修改器(modification)。输入点上,数据是已经求值后的不可变(immmutable)值,经由数据变换,数据的二次变换,数据的三次变换(可能是要呈现的记过),比如输出HTML。系统更多的像是一些管道相连的一大堆通用数据处理器。

当系统出现问题时,你可以检查输入/输出,或者直接模拟输入/输出来诊断问题。这个有点像是维修模块化的电子元件,方法通常有两个:

  • 你测量输入端的电流电压和输出端的电流电压,来确定这个电子器件是否按照预期工作。
  • 或者你逐个替换系统中的元件,直到你发现当某个零件替换后,系统正常工作了。

你如果观察维修小工,你会发现他会在这两个方法见频繁转换。

由于是同用数据结构和通用数据处理,这让复用变的可以预测(Predict),如果输入和输出可以达到你的需求,那么这个函数你就可以拿来使用。好像维修小工,并不在意某个电容是哪个生产商生产的一样,达到要求就能用。

现实例子

由于状态变化原来越频繁,面向对象缺点也就越来越突出,比如近年来的前端由纯展示(View)变成了应用(App)。所以使用JQuery来修改组件的状态已经不能满足需要了,现在的Component-组件化越来越成为主流。无论是Vue还是React,和其对应的ElementUIAnt Design,让你可以对组件细节不用关心而很好的使用和替换组件。你给组件以数据,组件做这个数据的变换,变成一种呈现方式。通过约定,或者一个转换器,同一组数据,你输入到ElementUIAnt Design出来的只是风格的偏好不同,而结果应该是一直的。

函数式架构的重点在于连接而构成的系统。通用的元件(数据结构)加上通用的变换(函数),而不是由一个个定制的对象(类型实例)而组成的,这样的系统很脆弱,坏了你没有办法维修和更换——因为都是定制的。

总结下来,当系统变得复杂以后,通过状态变化带来的副作用让系统变得脆弱和无法维护,而函数是的数据加通用处理机制会让系统工作的更好。

 

首发: https://www.imzjy.com/blog/object-oriented-design-retro

posted @ 2020-03-04 18:17 Jerry Chou 阅读(348) 评论(0) 推荐(0) 编辑
摘要: 死锁示例 如果你开发一个简单的Windows Form程序,点击Button去使用async异步获取一个数据,然后显示在Label上,类似这样的代码 private void button1_Click(object sender, EventArgs e) { var task = GetCont 阅读全文
posted @ 2020-02-27 13:38 Jerry Chou 阅读(1430) 评论(0) 推荐(1) 编辑
摘要: 一直对协程(coroutine)的概念不很很懂,看了Wiki中关于Coroutine的条目心里有点而谱了,至少知道协程是什么了。 通常我们的子例程,比如我们编程语言中的常用的函数,只有一个入口点(Entry Point),那就是你调用这个函数时执行第一行代码,出口点有可能有多个,比如正常执行完最后一行代码,再比如使用return语言在任意一点退出函数。而数据的交换通过参数和返回值来实现。并且这个... 阅读全文
posted @ 2015-01-01 17:53 Jerry Chou 阅读(640) 评论(0) 推荐(1) 编辑
摘要: 2010年12月1日加入当时的MRC,经历过EyeTrackShop,在到2014年12月底,Sticky整个部门被裁撤,我被外包出去做一些电信器材测试的相关工作。我从头到尾经历一个公司的从无到有,再到消亡。先前我也跟自己说好,无论如何要把这个完整的过程经历下来,现在我做到了。简单记录一下,以免很快... 阅读全文
posted @ 2014-12-21 21:09 Jerry Chou 阅读(357) 评论(0) 推荐(0) 编辑
摘要: 术 最近在带几个兄弟完成互联网项目,我是中途才加入的,其实他们开始的时候已七七八八完成的差不多了,前端的小伙临时起意拍拍屁股走人了。我觉得可惜,决定尝试去带他们产出一个好的结果。项目管理这样的事,难的就是相信项目可以成,并且按照心中所设想的按部就班的完成一个个小任务。考验项目的成败的往往是心力,而不是能力。在团队遇到困难,迷茫的时候,你是否依然坚定。这个坚定来自于两方面: 首先,你相信,并且知... 阅读全文
posted @ 2014-09-08 22:59 Jerry Chou 阅读(482) 评论(0) 推荐(0) 编辑
摘要: Google I/O 2014提出Material Design,这段时间听到不少关于Material Design的解读,至此Google已经定位了自己的设计语言,我个人看来就是Android和iOS设计语言更加接近了。 说到Material Design,首先要说的是乔布斯倡导的拟物化设计(Skeuomorph),在智能手机初期,明确讲是触摸屏智能手机的初期,想让人们去接受和理解一个新的材质... 阅读全文
posted @ 2014-07-01 11:21 Jerry Chou 阅读(1460) 评论(0) 推荐(0) 编辑
摘要: 最近在看DSL的东西,对于外部DSL,写一个解释器是必不可少的。我试图归纳一下我学到的,以写一个解释器为目标,讲一下如果来实现一个可用的解释器。一个解释器通常可以分为一下几个阶段: 词法分析(Lexer) 语法分析(Parser, BNF, CFG, AST) 语义分析(AST的处理, annotated AST) 目标语言生成(stack-based) 这里... 阅读全文
posted @ 2014-04-28 16:22 Jerry Chou 阅读(2636) 评论(0) 推荐(0) 编辑
摘要: 两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客:理解JavaScript中原型继承JavaScript中的原型继承这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误理解。今天看《Understanding Scopes》这让我从新思考了一下原型继承,更重要的是站在一个继... 阅读全文
posted @ 2014-04-21 14:23 Jerry Chou 阅读(630) 评论(0) 推荐(0) 编辑
摘要: Redis是一个偏重于in-memory的key-value数据库,这样讲有点儿不准确,但是很容易将Redis简单分类。更准确的讲Redis是一个数据结构的存储服务。它的value不仅仅只有string,他的value可以是下面几种:stringlistsetzset(ordered set)has... 阅读全文
posted @ 2014-04-16 11:10 Jerry Chou 阅读(1670) 评论(0) 推荐(0) 编辑
摘要: 下午的时候看最强大脑,我个人觉得这个个娱乐节目,仅此而已,谈不上什么科普。另一档中央台的《是真的吗》比这个科普性强多了去了。我比较讨厌的是他打着科普的旗号做娱乐,这会产生很大的误导。这期间更操蛋的是插播另农夫山泉的广告,说的是农夫山泉去东北找水源,坚持水源地建厂的原则,去你妈的什么玩意,你这不就是破坏环境吗?已现有的技术,想喝口干净的水并不困难,其实我觉得这样就够了,靠什么自然矿物质那大多是噱头。取来的水需要处理吗?处理,那么更普通水有多大的区别呢,不处理,那你敢喝吗?都什么玩意。我们现实生活在一个现代化的社会,我们能达到的高度很大程度上取决于你所站肩膀的高度。中国有很多传统的手艺,这些传统的 阅读全文
posted @ 2014-03-30 17:25 Jerry Chou 阅读(429) 评论(0) 推荐(0) 编辑
点击右上角即可分享
微信分享提示