【编程】是什么编程思想,让老板对小伙怒飙英文?Are you OK?

一个段子引发的思考

先讲一个段子:

说某公司的老板招了一个软件研发经理小李,希望小李能帮企业完成一款重要软件的开发。

入职第一天,小李就给老板发邮件:"你好,老板,你的商业模式有问题,屌丝们没啥钱,赚他们的钱死路一条,咱走高端路线吧,卖给土豪,嘎嘎赚钱。"

老板皱了皱眉,没回复他。

第二天,小李又给他发邮件:"隔壁项目组的项目一坨狗屎,肯定做不成的,老板你多留意一下!"

老板面有愠色。

第三天,小李啥也没发,但是人力跑来汇报,小李私下抱怨他接手的项目风险巨大,但从未向上反馈过。

老板坐不住了,给小李发了封邮件:

"Are you OK?"

段子结束。

请问,小李去的是哪家公司?哈哈,开个玩笑

请问,小李犯了哪些错误?你理解了小李在职场上犯得错误,那么你也就差不多理解了一种极为重要的软件编程思想。

"控制向下,信号向上"

1. 什么是 "控制向下,信号向上"

在前端编程界,有个非常常见的概念叫"单向数据流"
在游戏编程领域,也有个概念词叫 "控制向下,信号向上"
在企业软件的架构层面,下一层的组件通常作为上一层组件的"能力提供者"被调用。

抛开名词差异,他们的本质其实都是类似,内核殊途同归,人们从思想上有意识地把代码块划分成了两个大类:

  • 被调用者
  • 调用者

当然,任何组件都可以同时作为被调用者 ,和调用者

认识这种编程思想,理解它,可能对你的帮助不仅仅是在编程领域,对于职场的运转规则或者也能带来不一样的理解和体验。

让我们思考一个典型的编程场景:计数器

好的,现在你看到了一个经常作为入门demo 被拿来讨论的场景,让我们脱离具体的编程语言和技术框架,把它当成一种通用场景来进行抽象,我们大抵可以把它按"调用者"和"被调用者"拆成如下:

在上图中,我们不仅完成了一次组件设计上的分层,而且设计了最简单也最符合"信号向上,控制向下"的典型的架构。

"按钮"和"数字显示组件"作为层级更低的组件,在该架构中只有两个职责:

  • 按钮负责将自己被点击这个信号反馈给上层
  • 数字显示组件负责显示上层命令自己显示的数字

而"计数器"作为层级更高层级的组件,它需要完成的事项责更多:

  • 记录当前数字
  • 监听按钮的点击信号
  • 在监听后计算,获得计算后的数字
  • 控制数字显示组件的显示数字

这样,一个典型的"控制向下,信号向上"架构,就完成了。

同时,计数器也可以作为"被调用者",当它被调用时,它可以提供如下能力:

  • 向上发送信号:我的数字变化了
  • 被上方控制:重置计数

通过这样一层层搭建,你可以完成绝大多数符合业务的客户端页面。(浏览器当然也算客户端)

那么,这样做的好处是什么呢?

2. 组件的核心能力是被复用

为什么要对组件分层,为什么要把代码块抽象为组件或者工具方法?

答案只有一个:复用

软件工程的不可能三角大家都是知道的:

  • 效率
  • 质量
  • 成本

这三者在有限资源的开发过程中是不可能同时满足的,组件化可以在长期来看一定是对"快"和"好" 这两方面带来了显著收益的。

  • 快速的组件能力复用提升效率
  • 充分的单元测试提升质量

达成以上效果的核心,就是要保证组件能尽可能被更多的开发者、团队、项目复用,正是组件这种天然的需要被复用的特性,使得它一定需要满足以下特性:

  • 它的能力是面向"未知者"的。

一个"按钮组件"永远无法轻易预知未来自己会被用在怎样的场景下,它可能被用在双十一的购物车旁,可能被用在相亲网站的一见钟情场景,甚至可能被用来发动一场战争。

因此,错误的做法有一千万种:

尝试在组件内提前面向所有它可能面对的全部一千万种场景,包括控制调用它的那个组件+1计数,控制点击它的那个人爱上另一个人,控制一枚核弹完成装填等等...

而正确的做法只有一种:

无论调用者是谁,只要他监听了,便像他发送信号:我被点击了。

如图,以上两种设计模式,很显然"信号向上"是显著优于"控制向上"的。

这也正是为什么大家总是在强调"组件的单一原则性",不是组件不能做得更多,而是在面向复用这个核心内容的场景下:

少,就是多。

同时:

组件只有通知调用者的义务,却没有控制调用者的权利。

3. 组件的边界

组件到底应不应该和同层的其他组件通信,这是个设计问题。

还是刚才那个"计数器"的例子,让我们尝试一下"同层组件互相感知"的设计:

看起来也没什么问题是吧?

但是如果这时候设计变了,甲方提出了更符合实际的要求,点一下按钮要增加两个计数,那你将无法在"调用者层"完成业务更新,而需要去重新修改组件内部的业务逻辑。

而且,更致命的是"耦合"。

耦合是一个源自物理学的术语,核心含义是两个组件之间产生了非常紧密的互相依赖,单单任何一方都将无法正常运作。

在当前这个例子里:

  • 如果没有计数器:按钮将毫无作用,因为它只向数字显示组件输出信号。
  • 如果没有按钮:数字显示组件也毫无作用,因为它只接收按钮组件的信息进行更新。

很显然,组件在这种耦合中失去了自己在更广阔场景复用的核心能力。

用人话说就是:废了。

4. 调用者的向下控制

上面讲了"被调用者"这种身份呢的组件应该如何设计,那我们再来看一看身为"调用者"有哪些不同?

首先,调用者非常明确自己拥有哪些组件,它们分别具备什么样的能力。

以"计数器"为例,它在设计和实现时就能明确,它拥有:

  • 按钮组件
  • 数字显示组件

它的调用者,则只能通过调用组件提供的能力,来完成自己需要的功能。

因此,"调用者" 向下面对的是一个个具体的组件,它只需要确认两点:

  • 用户进行点击时,有组件把信号告诉我。
  • 我命令显示组件显示数字时,它能正常执行。

是不是很像职场上的"控制者"?

他们需要获得更多更为准确的信息,需要你及时反馈风险和进度,但不惜要你命令他去做一件具体的事情。

具体的事情谁来做的?当然,可能是他自己来做,更多的情况是他负责向下控制,交给更加专业的人来做。

而标准组件如果满足不了要求了,他们可以随时更换一个具备相同能力的组件,顶替到相应的岗位,整个机器依然能够正常运转。

相关推荐
尘世中一位迷途小书童4 小时前
版本管理实战:Changeset 工作流完全指南(含中英文对照)
前端·面试·架构
尘世中一位迷途小书童4 小时前
VitePress 文档站点:打造专业级组件文档(含交互式示例)
前端·架构·前端框架
甜瓜看代码4 小时前
666
前端
吃饺子不吃馅4 小时前
【八股汇总,背就完事】这一次再也不怕webpack面试了
前端·面试·webpack
Amos_Web4 小时前
Rust实战教程--文件管理命令行工具
前端·rust·全栈
li理4 小时前
鸿蒙相机开发入门篇(官方实践版)
前端
webxin6664 小时前
页面动画和延迟加载动画的实现
前端·javascript
逛逛GitHub5 小时前
这个牛逼的股票市场平台,在 GitHub 上开源了。
前端·github
Max8125 小时前
Agno Agent 服务端文件上传处理机制
后端