我比较好奇,对于非软件开发者,编程是什么样子?他们在多大程度上能理解开发者的工作? 也许开发者对编程太熟悉,已经忘了庐山在身外者眼中的面目。
我说下自己的想法,猜想一下编程为什么难以被普通人理解,以及怎样解决,解决了又有什么好处。
计算机虽然有看得见摸得着的实体,但它的原理仍然是非常抽象的(毕竟它几乎无所不能啊)。
虽然人人能处理像“父母,亲戚,朋友,水果,箱子,变化,值”等数不清的抽象概念,但计算机软硬件的概念,明显不是普通人会遇到的。
计算机的底层是指令级的精确。程序就是一条条精确的指令的集合。计算机执行指令的过程,就如同一个鼠目寸光的人,取过一条指令,根据指令的内容,作出非常非常精确的动作,绝不增减。
这个指令,在不同的层级,可以有不同的抽象,
但不管是哪一个层级,指令仍然是精确的。上层的指令看起来比底层更复杂强大,只因它封装包含了更多的底层指令。
举例来说,应用层的一个对一组数排序的指令,包含的是编程语言层的操作数组元素、比较数大小、循环等很多指令的组合,对应的计算机底层则是更多的内存读写,寄存器读写等指令。
这种对精确性的苛刻要求,对于普通人来说,无疑是一个迥异的思维模式(开发者就见多不怪了)。
对于抽象性来说,
一般来说,越上层的抽象越容易理解。像是 UI 组件、应用层 API 这些上层的抽象概念,尽管也是计算机世界的抽象,但对于普通人来说,毕竟不像天书了。但仅仅理解这些,对于理解计算机的工作原理,甚至对于理解开发人员的日常工作,也是不够的。因为大多数的开发工作,至少要熟悉编程语言层面的抽象概念,比如循环、判断、数组、字典、变量、取值、赋值、函数、类,甚至协程、线程、进程、消息、同步、异步等等。对于普通人来说,这些抽象概念就比较复杂了。
对于精确性来说,
假设普通人已经理解了编程方面的抽象概念,也能够通过上述的概念来操纵编程语言了。他还是要面临接下来的困难:怎样把一件由现实抽象而来的任务,从上层的抽象,逐级精确的分解为他掌握的编程语言指令。
仍以给一组数排序作为例子,在明白了 for 循环,if/else 判断,明白了数组,明白了怎样读写数组里面元素,明白这些抽象概念后,怎样完成排序这一任务呢?
因为对于普通人来说,排序是毋庸置疑的简单,显而易见的容易。但恰恰是这个“显而易见”,让他感到分解任务到编程语言的指令时,出现了困难。由模糊的“显而易见”到“精确指令”是他难以跨过的一道门槛。
其实不止是普通人,即使是开发人员,在写代码时,仍然会为边界条件而犯愁。明明知道程序的基本逻辑是对的,但如果各种边界条件处理不对,精确无比从而“挑剔”无比的程序就会“罢工”。
那么怎样解决“抽象性”和“精确性”这 2 个难题呢?
仍然以一组数的排序为例,假设使用冒泡方法来排序,则会用到数组、获取数组长度、数组元素读取、数组元素修改、变量、数的比较操作、循环结构这 7 个抽象概念。
为了解决抽象性,需要把这几个概念具象化和可视化。现在想象在一个计算机模拟的具象化三维世界中,学习编程的人,作为用户,要在这个具象化的世界中,完成排序的任务。他可以具象化地操作这个世界里面的具象物体。
为了解决精确性,需要在这个具象化的世界里,尽可能隐藏所有具象物体暴露出的信息,减少不必要的可见信息对用户的干扰,迫使他使用指令去获取。比如对于具象化为一排箱子的数组,数组里面数的内容应该是隐藏的,数组的长度信息也应该是隐藏的。用户只有使用指令才能获取。这样迫使用户在解决问题时,必须使用编程思维,而不是利用视觉思维。
其他指令的具象化,也需要注意,比如获取数组的长度,怎样具象化这个指令呢?获取的长度信息又要放在哪里呢?应该是放在一个变量里,因为获取长度信息,不是让用户去看的,而是为了给后续的指令来使用的。
还有不少抽象概念需要具象化,目前我还没有想清楚。
当用户在这样一个把所有编程世界的抽象概念都具象化了的环境中时,他不需要去考虑那些编程的概念,所有的概念都具象化为类似现实世界的事物。而当他在这样一个虚拟的“现实世界”中找到了问题的解法,那么简单变换,就直接得到了对应的程序。
更重要的,他已经是在使用编程的思维了。
最重要的是,他理解开发人员的工作了。世界上又多了一份理解,多么美好。
1
lewis89 2021-01-28 17:48:32 +08:00
因果一致性,吃饭 拉屎 擦屁股, 吃饭 拉屎 擦屁股
|
2
shendaowu 2021-01-28 17:51:05 +08:00
用 Brainfuck 向外行介绍编程?也许是个馊主意。
|
3
MakeItGreat 2021-01-28 17:53:16 +08:00 via Android
就和英语美术音乐体育这些一样
小时候学习快,长大了就慢了 |
4
opengps 2021-01-28 17:53:51 +08:00
外行人就不用解释那么准确了,相信我。你就说你是修电脑的,而且是啥也不会那种菜鸟,他们保证一听就懂
|
5
superliwei 2021-01-28 19:25:59 +08:00
不要尝试让别人理解,除非你欠他钱。
|
6
orannge 2021-01-28 19:40:12 +08:00 2
这是入行的理解,看电影需要理解演员的工作吗?人与人的理解就两个字,尊重。
|
7
namelosw 2021-01-28 19:55:58 +08:00 1
其实应该反过来, 程序员要让自己的代码更抽象. 但是大部分程序员做得并不好.
比如你说的数组长度, 正常人的思维就是长度, 就是直觉: list.length 如果你追问, 那么他们可以把直觉分解开, 搞得更具体一些: list.map(() => 1).sum() 再更具体一些: list.map(() => 1).reduce((x, y) => x + y, 0) 普通程序员的思维: while |
8
namelosw 2021-01-28 19:59:52 +08:00
不小心按快捷键发出去了, 接上:
普通程序员的思维 let sum = 0 while (...) {...} 所以写得更函数式或者更逻辑式一些, 反而和普通人的思维比较接近, 比如可以思考一下: 三角形三边长度都是整数, 三边之和长度小于 N, 一共有几种组合, 分别用 C 和 Haskell 写有什么不同 |
9
cmdOptionKana 2021-01-28 20:26:27 +08:00
具体是什么人不理解? 80 、90 、00 后对电脑和手机已经很熟悉了,如果对编程或程序员这个职业有一点兴趣,应该不难理解。
如果是对这方面没有兴趣的人,不管你怎么解释,他们也听不进去呀。 很多人所谓的不理解,要么是漠不关心,要么是有偏见(多数对这个职业没偏见,而是对具体人的有偏见,不管他是什么职业,都会无意或故意说几句那个职业的误解来调侃)。 不是难理解,多数人是没有去理解的意愿。 |
10
hxndg 2021-01-28 22:39:22 +08:00
从某种意义来说,程序员实际上提供的是一种有序的抽象。
但是从工作来说,程序员提供的是各种各样的补偿操作,要么牺牲这个换取那个,要么牺牲那个换取这个。 所谓的精确,很多时候都是无稽之谈。现代计算机并行体系并不保证你看到的就是稳定的结果,换言之提供地是一种承诺。只承诺什么是绝对不会出现。 至于对计算机而言,从本质来说是一堆一堆的协议套起来的。 |
11
favourstreet 2021-01-28 23:06:31 +08:00 via Android
Dijkstra 老师有句活:If debugging is the process of removing bugs, then programming must be the process of putting them in.
编程没什么神秘的,调试 Debug 才是开发人员真正的工作。教会一个普通人编程是很快的,但是学会 debug 却必须对计算机有通透的理解。 |
12
AmrtaShiva 2021-01-29 08:11:02 +08:00 via iPhone
理论说的天花乱坠 不如动手实战 做过了才能说有所理解
|
14
namelosw 2021-01-29 11:52:22 +08:00
@no1xsyzy 对, excel 就是个例子, 以等式为核心的.
像上面说的三角形, 用 Haskell 是 [ (a,b,c) | c <- [1..n], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a+b+c < n] 其实概念上就是几个类似的等式 /不等式拼起来, 只描述需求, 不说求值过程, 感觉上和用 Excel 就很像: c < n b < c a < b a^2 + b^2 == c ^2 a + b + c < n 这样的话, 和各种 for 循环检测 break, 挨个元素 push 进数组感觉上完全不一样了, 和大部分人的思维比较接近一些. |
15
sillydaddy OP |
16
namelosw 2021-01-29 12:59:53 +08:00
@sillydaddy
> 你说的这个三角形的问题,让我回忆起了在学校了解过的 Prolog 语言,看起来就是在描述问题。但是 Haskell 这种函数式编程语言也能做到吗? 现在想想这种语言还真是神奇。 函数式语言(其实不一定函数式语言, 普通语言有个语法糖就行)只能做到一小部分这种效果, Prolog 是对离散的问题都可以做到这种效果(但不保证停机). 现在的深度学习有点像一个积分版的 Prolog, 不只能解离散问题(王垠的博客里也提过这个观点). 实际上上面三角形的问题那个语法糖都是 Monad 和 Applicative 的变种. 有点类似于 JS 的 Promise.then 和 Promise.all. 或者列表的 map 和 flatMap 方法组合. [ (a,b,c) | c <- [1..n], b <- [1..c], a <- [1..b], a^2 + b^2 == c^2, a+b+c < n] 约等于 do let c <- [1..n] let b <- [1..c] let a <- [1..b] guard $ a^2 + b^2 == c ^2 guard $ a+b+c < n return (a, b, c) 中间还能脱糖一步, 就是变成>>= (flatMap / bind)和. (fmap / map)就跳过了, 下一步脱糖成类似 JS 的伪代码: [1..n].flatMap(c => { [1..c].flatMap(b => { [1..b].map(a => { return [a, b, c] }) }) }).filter(([a, b, c]) => a^2 + b^2 == c^2) .filter(([a, b, c]) => a + b + c < n) SICP 里面第二次解八皇后问题就是类似这样的 flatMap/map 嵌套, 跟第一次解比明显可读了很多. 这种嵌套模式巨常见, 不仅用在列表上, 还能用在 async, optional, stream 等等各种东西上, 所以很多语言都有语法糖. 其实 JS C#的 async await, C#的 LinQ, Scala 的 for, Rust/Swift 的?本质上都是这个语法糖, 实际的变换都是把看起来像一个变量声明套到一个类似 lambda 的东西里做参数嵌套, 前后前几步都是 flatMap, 最后一步变成 map. 这样其实就是一个很抽象的描述让计算机自己分解成具体过程的例子. Prolog 和深度学习就更高级一些, 干脆只写名字不写函数体直接调用, 给定 Facts 和 Rules 直接问结果, 所谓的“函数”都是电脑自己生成的. > 为啥我感觉 C 语言式的过程编程,也比较符合人的思维? 这个三角形的问题交给普通人来手算,他想出的解法应该也是分步骤的吧。 但是普通人不用分解, 或者不想分解. 他们的期望在高抽象的环境下工作. 比如产品经理或者老板, 他们的想法其实就是 wishful thinking, 只要逻辑上说得通, 实现只是细节, 那么细节其实就交给程序员了, 程序员就是他们的计算机. 理想情况下, 如果程序员能把自己的工具抽象得很好, 其实就减少了工作, 聊聊数句把 specification 以严谨的语言告诉计算机就可以了. |
17
php01 2021-01-29 13:03:30 +08:00
编程很简单,但是总有人为了展示自己所了解的,将这东西说得天花乱坠无比复杂,从而体现自己那虚无的满足感甚至是优越感。
这就相当于一个三岁的小朋友问你什么是数学,你跟他聊微积分并且说这是基础,不懂这玩意,你就不懂数学,只能做个简单的计算处理工作,没出息,低端,以后活该被卷。 这事是不是很离谱。但是放到编程这一块,让一些人跟外行解释这是干嘛的,这就是常态。 我想对这些人说,21 世纪了,自信点。 |
18
php01 2021-01-29 13:06:20 +08:00
三岁小朋友,刚开始你只用教他 1-99 就行了。0 都没必要教,只要教他 100 最大就行了。甚至不用会写,只用从 1 数到 20 就行了,都不需要一直写到 99,因为后面只是重复。我相信我们都是这么长大的,循序渐进。到这里,上来就是高等数学,上来就是算法导论,干嘛啊。
|
19
no1xsyzy 2021-01-29 13:31:30 +08:00
@sillydaddy
@namelosw 这其实是 top-down 和 bottom-up 两种形式,具体展开就是哲学认知论的范畴了。 这点,大概可以参考下 pandoc 是怎么写的(毕竟作者是哲学教授还主攻认知论方面 |
20
BingoXuan 2021-01-29 13:35:45 +08:00
我见过最简单的方法去理解就是表格( checklist ),从第一项开始写,你需要干什么写什么,程序会自动一一执行,只要跑到最后就是完成。所以楼上以 excel 举例其实是 ok 的,但 excel 对于更普通的人来说还是太难理解。
|
21
0o0O0o0O0o 2021-01-29 13:43:24 +08:00
「 难以被普通人理解」
我觉得你可以稍微定义一下「 普通人」和「 理解」 零基础借助搜索引擎装好 vscode 配好 python 环境写个循环成功跑起来,算理解吗? 比如有些没接触过编程的人,突然对编程感兴趣,可能只是想用编程平时搞搞自动化处理点文档,你上来就按照科班从业的标准来喂东西,大概率会让人厌倦和沮丧吧。 例如,作为普通人,我觉得连你举的例子都是下意识地「按照科班从业的标准来」而不是「 让非从业者在一定程度上理解从业者的工作」: “我的确需要用到排序但我为什么要学那些乱七八糟的排序算法?会搜索能看着文档来写真的不行吗?现在还有多少高级语言不自带 sort 吗?没有的话我能换一门吗?” |
22
grewer 2021-01-29 14:07:15 +08:00
多学数学 很多数学专业一转计算机就是大神了
|
23
sillydaddy OP @0o0O0o0O0o #21,
你说的很好,我承认举排序的例子,确实是从开发的角度来考虑的,因为里面有各种编程的要素嘛。。这么看来,我已经变得不理解「 普通人」的思维了。。悲剧! @BingoXuan @php01 想到这个主意,是受到市面上一些游戏的启发,可以通过玩这些游戏来体会编程的思维。 比如下面这个,Cargo-Bot https://www.douban.com/game/26393479/,可以在线玩耍,https://altermanchess.wixsite.com/cargobot 它不需要教你编程的概念,但在游戏过程中,自然而然体会到编程的概念。非常自然。有不同难度等级,循序渐进。 |
24
ohoh 2021-01-29 14:59:44 +08:00
用箱子从大到小排序举例, 用程序肯定首先就要搞清楚是按体积, 高度, 还是表面积.
普通人怎么排? 按感觉来咯. 什么你还要我搞清楚长度? |
25
systemcall 2021-01-30 18:59:08 +08:00
看《系统化思维导论》
|