像机器一样思考(三)—— 穷尽就是力量

经过前两篇的内容学习,我相信大家已经差不多学会了这个思考模型。本篇的重点是用它来解决更复杂的问题。当我们开始解决一些稍微复杂点的问题的时候,我们会发现差不多的态度是不行的,我们需要严谨的态度进行缜密的思考才能真正发挥出这个思考模型的力量。

慢慢你会发现,这个思考模型本身不会让你思维缜密,而思维缜密了才能用好这个思考模型。它带来的最大的好处,是让你自己开始看到自己思维的欠缺,从而不再是个思维世界的盲人。

穷尽

那么,我们开始做点复杂的题目。也没复杂多少,我们扩展一下上一篇的题目,算学生的成绩单:

打印所有人的成绩单。已知输入的格式是

["学号", "学号", "学号"]
比如:
["TWA20160101", "TWA20160102", "TWA20160103"]

我们有一个全局函数可以给我们提供所有的学生的成绩:

function loadAllScore(){
    return [{
        name: "张三",
        id: "TWA20160101",
        chinese: "95",
        english: "80",
        math: "95",
        programming: "80"
    },
    ....
    ]
}

要求打印出成绩单类似于:

成绩单
姓名|数学|语文|英语|编程|平均分|总分 
========================
张三|75|95|80|80|82.5|330
李四|85|80|70|90|81.25|325
========================
全班总分平均数:xxx
全班总分中位数:xxx

仅对这个题目进行划分,我们一定觉得很简单,对吧。就仿照着之前的写呗:

#1 生成成绩单view model
输入:
  studentIds: [String]
输出:
  scoreSheet: {
    studentScores:[{
        name: String,
        chinese: String,
        english: String,
        math: String,
        programming: String,
        average: String,
        summary: String
    }]
    summary: {
      totalAverage: Number,
      totalMidden: Number
    }
  }
#2 打印成绩单
输入:
  scoreSheet
输出:
  result: String

我相信很多人都是这么想的,然而不幸的告诉这么想的同学,这种写法是错误的。原因其实也很简单,请问,#1输出里的chinese等成绩是怎么得到的呢?没有来源吧?你说你调了loadAllScore函数?那为什么不写在输入里呢?

所以说,我们遗漏了一些输入。回到我们开始的标题上:穷尽。

可能有很多人听说过一个分析问题的基本原则:完全穷尽,各自独立。很多人听到这个时候,会很困惑:穷尽什么?独立什么?经过我们这些练习,我相信在编程领域,你们这个困惑会小很多。

所谓各自独立,说的就是在我们划分任务的过程中,每一个任务都对应一个代码块或一个函数,这些代码块和函数,是互相不包含的(不是不依赖,这是翻译的问题,各自独立的独立指的是Exclusive不是Independent)。

所谓的完全穷尽,说的是我们需要穷尽这个代码块或函数里所有的输入和输出。不能遗漏任何一个输入,任何一个输出。我们的每一项,它的属性,也不能有遗漏,我不能说分析studentScores只想到部分属性,比如说:

studentScores:[{
        chinese: String,
        english: String,
        summary: String
    }]

这样是不行的。如果我们不严于律己穷尽所有的数据项,我们就会在写代码的时候遇到各种问题。能否穷尽与否,也看出来你思维的缜密与否。

是不是开始感觉到麻烦了,刚开始做的时候是有些慢的,但我们坚持穷尽这个好习惯,就会渐渐的感受到自己能力的成长。如果你穷尽了所有的输入输出,那么各种可能遇到的问题就像是如来佛手里的孙猴子,无论有什么变数也尽在你掌握之中了。

那么如果我们穷尽输入输出的话,我们这个题目真正的任务应该怎么分解呢?可以写成这样:

#1 获得学生成绩
输入:
    studentIds: [String]
    studentInfo: [{
        id: String,
        name: String,
        chinese: String,
        english: String,
        math: String,
        programming: String,
    }]
输出:
    studentScores:[{
        name: String
        chinese: String,
        english: String,
        math: String,
        programming: String,
        average: String,
        summary: String
    }]

#2 计算总计
输入:
    studentScores
输出:
    summary: {
      totalAverage: Number,
      totalMidden: Number
    }
    
#3 打印成绩单
输入:
    studentScores
    summary
输出:
    result: String

可能你会奇怪,为什么会分成3步呢?或者说,我们该怎么判断分几步呢?这其实没有一个标准答案,我建议初学者尽量步子小一点,多分几步,经验丰富的人就可以步子大一点。不过有一个反直觉的经验可以分享给大家,你步子大了,开发速度不见得快,因为人是会犯错的。

这个题是写出来了,但是我们还是不太清楚怎么穷尽对吧。说是穷尽输入输出,到底输入输出都有多少大类呢?这个也是可以穷尽的。

输入总共有下面几大类:

  1. 参数
  2. 读取全局变量
  3. 调用全局函数后得到的返回值
  4. 读取局部作用域变量(比如this)
  5. 调用局部函数后得到的返回值
  6. hard code的数据

输出总共有下面几大类:

  1. 返回值
  2. 修改全局变量
  3. 调用全局函数时传的参数
  4. 修改局部作用域变量(比如this)
  5. 调用局部函数时传的参数

来去

听起来不错,不过从哪来,到哪去,还是要写清楚的,我们的studentInfo从哪里来?我们的result又到哪里去了?加上这个来去,我们最终的版本是长这个样子的:

#1 获得学生成绩
输入:
    studentIds: [String]
    studentInfo: [{
        id: String,
        name: String,
        chinese: String,
        english: String,
        math: String,
        programming: String,
    }]: loadAllScore()
输出:
    studentScores:[{
        name: String,
        chinese: String,
        english: String,
        math: String,
        programming: String,
        average: String,
        summary: String
    }]

#2 计算总计
输入:
    studentScores
输出:
    summary: {
      totalAverage: Number,
      totalMidden: Number
    }
    
#3 打印成绩单
输入:
    studentScores
    summary
输出:
    result: String: console.log()

练习

引入加分策略
少数民族 +10分
体育特长 +20分
艺术特长 +15分

题外话

好像输入和输出的可能性太多了,这很容易让人乱啊。
是这样的,所以为什么到了函数式编程我们需要强调纯函数,只有一个输入来源和一个输出去处,一般来讲就是输入只有参数,输出只有返回值。所以你看,如果你把一个领域都穷尽掉,你也会自己发明出那些靠谱的实践,换句话说,如果你能在用这套思维模型的过程中逐渐发现跟各种最佳实践都很容易配合使用,那就对了。(其实也不是什么配合使用,因为它跟代码是等价的,所以容易写代码的方法就容易用它,这是当然的。)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容