远隔天涯

我跟大家开的一个玩笑,经常在每当大家指出我如何如何就活不长久的时候说出来,"我以后是咱们里活得最久的一个,然后挨个给你们写传记,编派你们。哪个子孙要是说我瞎写,我就指着他说,那时候你出生了么,你知道个啥。"

但是有时候我也怀疑,我能不能活过你们所有的人。或者,在你们全都离开以后,剩下的时间够不够我写完。

所以,趁我们还都活着的时候回忆一下。

我所有的同学里,已知去世的,一共5个人了。每一个当我们回忆起来的时候,都一阵唏嘘。除了在大学就去世的那位,其余的都是在喝酒前或喝酒中听说的。每一次我都想说,让我们这杯敬给某某,他不能跟我们一起喝了也。我不敢说,怕你们大家一起哭出来,或者我一个人哭出来,那岂不是更糟糕。我知道,你们也是这么想的。

即使我们都生活在这同一个世界,大都也远隔天涯。远到,另一座城市,铁路或航线的另一端。因为求生,即使上了车就可以端起书隔开喧嚣,其实那也很久。从离开家到站台,从另一个站台到你的居处,分别需要1个小时以上。比如从沈阳或哈尔滨到长春,不是1个小时,而是3个小时以上。再加上请假和各种任务的拖延,加上往返劳顿以后的休整,就想,也许以后吧。我已经很久没能把当天的任务完成,然后非常放心地看碟、打游戏、喝杯咖啡。咖啡大多数时候是兴奋而不是享受。我也已经很久没有探望任何一个同学了。
trees

shadow_tree
我和我爱人去探望过一位师兄,最近又联系上了,发现虽然换了若干手机,他的名字在我现在的手机里还是写好的词组。我去看他的那个年代既没有手机也很少有电话,所以我也没有预约,就突然出现。他刚好安排了家教,把我们安排在他家那么大的房子里以后就跑了。过了一会儿,他爱人也要去家教了,我们才意识到自己唐突,也跑了。跑得仓皇,把一本机械工业出版社的关于需求或者测试的小薄册子丢在了他家。后来他问起过,我说就放在你那儿吧。已经15年以上。

这位师兄是我景仰的想成为的那种人。

他当年高考失利,似乎被他爸揍了 (?)我见过他的父亲,完全不像会打人的样子。被揍以后他就跑啦,从内蒙古随便搭了一辆火车,朝着远在天涯不知道什么地方。我不记得他说的是过了多久,也不知道当年那段路程需要跑几天,他吃的什么。总之,下了火车以后,他就到了北京。

他讲的时候,我的脑海里就浮现出浅丘戈壁,风吹草扬。少年就这样离开家乡,下车的时候看到满眼绿车皮长长的列车,一排又一排。

我问过,那后来呢。他说,后来就回家了,再挨揍。我不记得是当年,又或者是下一年,他就考到了东北师大。

他下一年,我也来了。迎新晚会是在新共教,那次演出是我从未见过的,大学生活的开始,原来可以这样。这位师兄和后来我的大哥合唱一首《青春》。一个人蹲在地上,举着话筒,另一个人坐椅子上抱着吉他。我当时惊叹,这就是友谊啊。GXX唱《舍不得你的人是我》 (感谢郭勇纠正) ,他后来的媳妇在一群白衣少女中为他伴舞,这里面不知道哪个女生跑进圈里为他献花。我一拍大腿,这就是爱情啊。JYX和PY唱《糊涂的爱》,后来他们就恋爱了。主持人介绍JH老师,最高一级的同学 (几乎全是男生)一齐起哄,因为前几天她还是师姐。后来我最初执教的时候,也刚刚不是师兄,现在师弟兼学生们还偶尔回忆起来。
java
后来,和这位师兄,我们还一起参加过教师技能大赛。他是霹雳舞的天才,整个人看起来就是那个样子。前几天一位同学来访,我们回忆起当年共同认识的一些人。她说,她记得93年有个男生,是什么什么样子。我立即脱口而出,那是谁谁啊,他跳霹雳舞蹈特别好,他是不是整个人看起来就像是踩在弹簧上。在那次教师技能大赛上,有才艺表演,他就跳霹雳舞,把我们从电影里看的各种动作全来了一遍。从来没有想过,这样的动作真人也是可以做出来的。他就像体操运动员一样,充满力量地跳来蹦去。嗯,原来小流氓们的舞蹈也可以在大学校园里跳啊,如果我会打口哨一定要来一声响的。

后来我们喝酒的时候,师兄说,他上场以前特别紧张,走来走去都不对劲,就觉得要出事。后来,女主持人走过来告诉他,"同学,你拉链开了。"然后他做了一个拉裤子拉链的动作。他就不紧张了,上场非常带劲,完全成功。我和大哥听完以后哈哈笑。笑完我就问 (很多年,我一直是这种理解水平,你习惯就知道了),"她说你拉链开了,你怎么就知道是裤子?"师兄说,"我浑身上下就这一个地方有拉链啊。"

这位跳霹雳舞的大侠,帮着同学出主意怎么对师妹表白,如今佳偶的孩子已经十多岁了。这位跳霹雳舞的大侠,在我另一次去看他的时候对我说,你当年青睐过的女生啊,现在已经是个非常普通的女人罢啦。这位从内蒙敢跑到北京的少年,居然住着大房子,跟老婆两个人出去家教,我那个时候实在很难接受。

我非常想问,你的梦想呢。而且这句话你可以想像语气。我们那个时候,从来没有师兄学长这样的尊称,都是三个字直称其名,我现在仍然觉得只称后两个多么暧昧。

我没有问,我觉得没有了梦想,或者换了梦想的人,不希望被问。更何况你远远看着,希望成为的那个人,你不希望他给你讲一大屁股做人的道理。如果那样,我就只想说滚,大家连怀念就都没有,有什么好。

有些师兄师姐和同学后来的样子,在另一个故事里有提到,这里略过。

但是!

他从来没有丢弃他的梦想,还是那样的少年。或者说,在做着本职的同时,他的身上也仍然满是那个唱着民谣疯狂地跳着舞蹈的少年的影子。

这次联系上是从大哥那要来这位师兄的微信。加上以后照例一顿扯屁。近照给我看看,还剩多少头发之类的。他发给我一张光膀子上篮的照片。在他的朋友圈里,我看到他炫两把吉他,光洁如新,弦声若空。

我突然想起大哥提起这位师兄前几年抱怨沈阳不让骑摩托了。我当时说,不骑不骑呗,那么危险。大哥说,你懂啥啊,又说,不骑不就白买了吗。我说,一个摩托能有多少钱。大哥说,八万。我说,八万能买一辆很不错的车啊。大哥说,那也不是摩托。

这两年他跟大哥电话的时候,提到要做万有引力常数测量装备。我说,电话给我,我来我来。我说,"那叫卡文迪许扭称",然后一顿否定。可是,他敢于和愿意做这个我记得需要一座山来帮助测量的装置,而不是问"师大附中最近有什么题啊""你打字速度有多快啊",这本身就多么令人向往。

这样疯狂的同学,居然还活着,还是按他原来的样子活着,活得还不错。前几年还能揍学生。这多么令我欣喜。他在照片里满脑袋黑的白的头发扬起来,对我竖起中指,咧着嘴笑得像个傻瓜。我很高兴。
green_leave
这位同学远在沈阳,和我3个小时的车程。大哥大婚的时候他来了,因为晕车,大哥陪他从车站走到学校,我似乎出差去了。我去过沈阳见他两次,很多年没再去。没有像当年那样电话也不打信也不写,突然就跑到学校办公室敲门。其实即使在同一个城市,在同一个校园,也是这样。

建一同学和我在同一城市,铁子老弟和我在同一校园,都已久未谋面。他们都在忙着各自的事情,我在忙着理各种乱七八糟的线头。如果不是有共同的事业,人生很难在错开以后再有什么交集,除了喝酒买醉的时候。

更不用说,我那些已经离开的同学。想再相聚一叙一饮,唯有百年。恼了散了不得相聚,还可以偶尔微信电话,那些人和相信他们的那些人,没有"哪天再聚",而是永不能相见了。

不过我也想,如果不得相见,近在一城,或者远在天涯,或者是生死相隔。有什么分别?

有的。

那就是,如果你还活着,像我的这位师兄一样活着原来的样子,在世俗之中又能安身立命。你既能跟世人胡吹海塞,也能偶尔让我看到你弹吉他的样子,看到你终于架起HAM天线的时候,看到你忙完世事终于坐着火车路过西伯利亚的白桦林。

看到你看着我的文字哈哈大笑或者热泪盈框。

又,我发现个秘密。如果用五笔打字,打出文字颠倒来,是一种疲劳程度,如果打出音同字不同的错误来,就是累得必须休息了。
keyboard
----

下面是与正文毫无关系的 emacs lisp,用于把 excel的cvs转成 markdonw 格式的 talbe。因为有更好的替代品,我不会再维护,扔在硬盘里就找不到了,估且存在此处,不另文发布。

(defun cvs2md-table ()
"replace cvs format to markdown talbe."
(interactive)
; , -> |
(goto-char (point-min))
(replace-string "," "|")
(goto-char (point-min))
(replace-regexp "^" "|")
(goto-char (point-min))
(replace-regexp "$" "|")
; table head
(setq col-count 0)
(goto-char (point-min))
(setq col-count (count-matches "|" (line-beginning-position) (line-end-position)))
(goto-line 2)
(setq head-count 0)
(while (< head-count col-count)
(insert "|:--")
(setq head-count (1+ head-count))
)
(insert "|")
(open-line 1)
; delete "||" in the last line
(goto-char (point-max))
(beginning-of-line)
(kill-line)
)

------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

猜测在学习新工具中的作用,一个实例

1.

当年我参加李YL老师组织的Linux内核源码讨论班,大家坐教室里,人手一本厚厚的《Linux内核源代码情景分析》。多厚呢,上下册,单册800页左右。我们都把书摊在桌面上,举起来太累了,听轮值的某个人讲,说我看到哪哪儿了,这一段的意思是啥啥,这段代码引用了某个数据结构,在哪哪页呢,那个人讲,我们就哗哗翻书。

用翻书的办法讨论,因为那是2002年前后,教室里没有计算机,没有笔记本,没有投影仪,也没有平板。

轮到我讲了。我讲了两页,然后提到某某处我猜是怎么怎么回事,假设如此,那么我们继续往下看,某某段的说法就容易解释。在我结束的时候,康凯同学点评,他说: 杨老师你不能这么整啊,咋能"假设"呢,你应该找*到底*是什么回事。我问,在哪找,咱们没机器代码查起来慢啊。他说:在书上找啊。

我拒绝了他的读书方法建议,答复如下。我本科是学电子的,是物理系出身,我所受到的教育就是,先假设,然后用实验事实证实或推翻假设,从我假设以后书上后面的那些段落,都是用来证实或推翻我的假设的依据。

2.

这让我想起书上讲的妈妈给孩子讲睡前故事。妈妈每当讲到关键时刻,就对孩子说,你猜后面会发生什么呢。然后孩子就自发地产生了编故事的能力。书上是这么讲的,我妈没给我讲过睡前故事,所以我也不知道是不是真的。不过,听说过一千零一夜故事,我担心那孩子被悬念勾着更睡不着了吧。

当听到真正的故事时,还会和自己头脑中的对比,"这不合理,杜丘怎么就会忘了装子弹","这个设定太取巧了,谁能想到杀人犯还有个双胞胎"。

我们在听故事的时候,对情节和人物确实是有预设 (猜测) 的。知识不仅来自书本 (!),而且来自猜测。然后我们需要根据猜测设计实验,检验我们的猜测正确与否。如果猜测对了,我们就快捷地得到了新的知识,虽然书上可能没写--书上并未写全你要用到的所有的知识,所以也不要预期可以依照书本生活和工作。

猜测-设计实验验证-使用知识,这是成熟的工程师区别于初学者的一个重要标志,因为工程的一部分正是实验科学。我很多年以后才知道,从培根的实证主义到波普尔的证伪主义,到罗素的对一致性的追求,设计实验的朴素观点背后还有哲学理论的支撑。

不知道这么年过去了,康凯同学对当年的讨论作何感想。他们毕业的时候聚餐叫我去喝酒,刚好没有成行,所以没有来得及问他那时的看法。不过计算机系的同学可能因为缺乏充分的实验,所以一直以来给我这样的印象,重课本而轻实验设计。谷同学和孙同学曾经非常惊讶地对我说:鞠同学怎么可以这么做呢,她根本不知道书上确切地是怎么写的 (当然也不知道知识是不是就是那样) ,就说,那咱们试试吧;一试,行,就说咱们就这么整吧。我当时的评论,这正是鞠同学厉害的地方。

猜测是建模/谓词判断/命题,设计实验是根据逻辑推论--如果猜测正确,那么这样设定实验,结果该当如此,如果结果不如此,那么猜测是错误的。这样,猜测-设计实验验证,以后我们就得到了新的模型/定理,作为工具可以应用于符合条件的场合,用于预测结果,用于改变环境。

老师有的时候提到"学活了"或者"学死了",区别大体指的就应该是这个吧。

3. 一个实例,用rrdtool提取cacti数据

以下的故事,用以展示猜测在整个学习使用新工具流程中的位置。

3.1. 要显示流量,读cacti,是图片,不能 XML parse

需求是这样,要在程序中显示校园网各汇聚层交换机的流量 (上行和下行)。你可以想像客户站在大屏幕前,指着天气图说,你看就是这条线上的数据,要显示在这里这里和这里。

%e5%a4%a9%e6%b0%94%e5%9b%be2

天气图是cacti展示出来的,cacti是网络流量监控的图形化工具,配置以后通过cacti已经可以查看各汇取层交换机的流量数据了,点击线路,就可以看到。

%e6%b5%81%e9%87%8f%e5%9b%be

凡能看到的,就能抽取。所以主力研发郑同学就说,那我先研究一下 java httpclient 吧。我否定了这个计划。我否定的并非使用 httpclient,而是投入时间去尝试学习研究,而是先假设这一部分不会有问题。httpclient是著名的apache的项目,而且濮同学早就用过,所以是确定地技术路线,没有风险。反倒是另一件事情有高风险,并非"凡能看到的,就能抽取"。httpclient能模仿浏览器的各种行为 (js解释呢?),但是 xml parser 部分 图片是不可以"抽取"成文字的。只要没有变成文字,那么就不能放心,客户可能打算换字体字型字号呢。万一天气图里的数据是图片,httpclient这条技术路线整体需要放弃。

天气图里的数据是图片。

而且从图片的 caption 和 URL 里得不到文字。

故事的第一幕就此结束。英雄遇到灾难,离开故乡,开始历险。

3.2 cacti数据可以用rrdtool读取,UNIX时间戳,zhumao同学说

我和向龙同学分别对着自己的显示器,显示器后面很多公里线路以后是郑同学,我们都愁眉苦脸。zhumao同学催,啥时候能去吃午饭呐。我敲键盘,"要完了啊。"

zhumao同学远程说,cacti的数据都在数据库里,可以抽出来。

峰回路转,午饭可以下咽了。

下午,我和向龙同学研究从哪个"数据库"里抽数据。向龙介绍cacti的数据库配置的是mysql,然后我俩把mysql数据库翻个遍,各个表,各个字段。从尺寸上看就不会容纳那么多日志。

但是zhumao同学技术上很可靠,应该不是虚言。所以我们判定,"数据库"一词不是指关系型数据库,而是泛指能存信息的容器。

zhumao同学远程说,抽取的工具是rrdtool。过了一会又说,时间节点用的是UNXI的1970年时间戳。

希望重新燃起,我看到大半夜的微信上向龙同学和郑同学进行各种尝试。

3.3 猜不到数据在哪里

我以为故事快结束了,但是向龙同学和郑同学说,"猜不到数据在哪里"。

"不是说用rrdtool么,zhumao用过啊。"

"zhumao只是说可以用rrdtool,他并没有声称自己用过。"

郑同学已经把rrdtool的语法研究得八九不离十了,就是抽出来的数据和天气图上显示的对不上号。

故事一般都是这个路线,一到关键时刻--钥匙就丢了,计算机刚好没电,掌握密码的人被打死了,主角的最主要助手突然叛变,"其实我是卧底"。为什么到关键时刻才会这样,之前一点也不。因为关键时刻是这么定义的,出现了困难的时候,如果不能克服,那就是完蛋。而在实验和工程中,每一个困难如果不能克服或者绕过去,那么就会完蛋,所以有N多关键时刻。比看警匪片和侦探故事还刺激。

4. graph properties 可以查看源代码 rrdtool graph

向龙同学提供我授权登录cacti (天气图及设置) 和 ssh到rrdtool工具所在操作系统,更关键地,他随时提供给我现场的部署、状态,比如天气图上的线路和rrdtool数据库的对应关系,他和郑同学尝试过的指令和结果。

长弓已经架好,重装步兵阵列在前,巨龙就在前方洞穴之中,只差最后一击。当然,这一击以后发现还要再出击N次也是常有的事,不过如果这次失手了,那就是最后一击,然后我们全军覆没。

4.1. 猜测及实验验证

zoom_graph
向龙给我展示的是这张图。整张chart以及图例和注释全都是一整张图片,PNG格式。我确认了我看到的和战友们所看到的相同。天气图是一张图片,我在郑同学这样声称以后也确认过一次。

猜测: 这张图是此刻实时生成的,是从"数据库"里读出来的,不是原来在磁盘中的。

否定: 向龙指出,zhumao在磁盘确实找到过这张图片。 (赞叹zhumao的反向工程能力)

再猜测: 磁盘里的这张图片也应该是生成的,用rrdtool工具从"数据库"里读出来,然后生成的。

猜测的依据: rrdtool 是 round robin database,文本或压缩文本的存储效率要比图片高很多。理智的设计不会存储图片。

鼠标在图示右上角的小扳手上悬停,显示tips为 properties,左键单击,是这个界面。

graph
长得真是如我期待,上面是代码,下面是代码生成的图。

那段代码是:

----代码开始----
/usr/bin/rrdtool graph - \
--imgformat=PNG \
--start='1474880074' \
--end='1474880360' \
--title='H3C12508 - Traffic - Ten-GigabitEthe' \
--rigid \
--base='1000' \
--height='120' \
--width='500' \
--alt-autoscale-max \
--lower-limit='0' \
COMMENT:"From 2016/09/26 16\:54\:34 To 2016/09/26 16\:59\:20\c" \
COMMENT:"  \n" \
--vertical-label='bits per second' \
--slope-mode \
--font TITLE:10: \
--font AXIS:7: \
--font LEGEND:8: \
--font UNIT:7: \
DEF:a='/var/www/html/cacti/rra/h3c12508_traffic_in_190.rrd':'traffic_in':AVERAGE \
DEF:b='/var/www/html/cacti/rra/h3c12508_traffic_in_190.rrd':'traffic_out':AVERAGE \
CDEF:cdefa='a,8,*' \
CDEF:cdefe='b,8,*' \
AREA:cdefa#00CF00FF:'Inbound'  \
GPRINT:cdefa:LAST:' Current\:%8.2lf%s'  \
GPRINT:cdefa:AVERAGE:'Average\:%8.2lf%s'  \
GPRINT:cdefa:MAX:'Maximum\:%8.2lf%s\n'  \
LINE1:cdefe#002A97FF:'Outbound'  \
GPRINT:cdefe:LAST:'Current\:%8.2lf%s'  \
GPRINT:cdefe:AVERAGE:'Average\:%8.2lf%s'  \
GPRINT:cdefe:MAX:'Maximum\:%8.2lf%s'
----代码结束----

"/usr/bin/rrdtool",这是一段命令行。

ssh到服务器,向龙告诉我去哪里可以找到 rrdtool 和 数据库文件。我跑了一遍上述代码,输出一个png文件到文件系统中,正是我想期待的。

故事发展到这里,我们知道,"/usr/bin/rrdtool graph"及正确的参数可以从数据库中抽取数据。只是抽取得到的形式还不尽人意,我们想要文本,得到的是图片。

就此验证zhumao的猜测都是正确的。

事实上,在另一条分支上,向龙和郑同学走得更远。他们已经得到了纯文本的结果,用的指令是"rrdtool fetch",只是抽得的结果还没有与天气图对应上。"rrdtool graph"直接证实了zhumao的猜测是正确的,抽取数据可行。

4.2 手册

运维和编程的著名格言: RTFM -- Read The Fxxking Manual.

我找到官方站点,[https://oss.oetiker.ch/rrdtool/doc/index.en.html],去读手册。此前郑同学也已经独立到过这里。

然后我根据 rrdtool graph 手册解释了刚刚那段代码里的这一小段

CDEF:cdefa='a,8,*

其含义中的重点是: 乘以8. 因为数据库里以字节为单位的,输出的图形是比特为单位的。

我执行了下面这段
----代码开始----
$ rrdtool fetch h3c12508_traffic_in_190.rrd \
> --start='1474880074' \
> --end='1474880360' \
> AVERAGE
traffic_in         traffic_out

1474880100: 1.9393791780e+08 4.9525977422e+08
1474880400: 1.9499877230e+08 4.8637343825e+08
----代码结束----

然后手动 (用 windows calc)计算

traffic_in :
1.9393791780e+08 * 8/1000000000 = 1.5515033424
1.9499877230e+08 * 8/1000000000 = 1.5599901784
平均值为 (1.5515033424+1.5599901784)/2 = 1.5557467604
作为对比,图示中的数据 Inbound 为 1.56G.

traffic_out :
4.9525977422e+08*8/1000000000 = 3.96207819376
4.8637343825e+08*8/1000000000 = 3.890987506
平均值为(3.96207819376+3.890987506)/2 = 3.92653284988
作为对比,图示中的数据 Outbound 为 3.93G.

抽取出的数据与图示吻合了。

4.3 放大图示,对比数据,向龙同学说

我展示方法,向龙同学说,我乘以8了啊。我问你从哪边往哪边乘的。他说,因为不确定到底如何,做了不少猜测,从两边分别都乘过。这是本故事的另一个寓意了,猜测的时候如果知道那样一定正确,尽可能减少其他可能,就更好。不就此展开。

事实上,这个实验的最后一击并不那么简单。向龙同学提供了对比数据的spec说明: 放大图示到某个具体的分钟,抽取的数据与这个具体的分钟的数据对比,避免在时间段内平均等造成的误差 (和复杂性)。同时,向龙同学提供了放大图示的手段,郑同学此前不知道放大的方法,我没有想到选取具体的时间节点。

4.4 时间转换,双向;新的关键环节:时区

有的同学可能已经注意到我上面引用的代码中的时间是UNIX时间戳,这是zhumao提示的。具体使用的时候,我的时间戳来自两个来源,(1) 从 rrdtool graph 的代码中抄,(2) 利用在线工具 [http://www.epochconverter.com/] 双向转换。

epoch

我这样找到在线工具的, bing: unix time stamp convert,然后右上角"Switch to Bing in English"。第一页前几个就很好使。

(3)命令行工具,Linux内置

----代码开始----
$ date --date='2016-09-26 17:02 CST' +%s
1474880520

$ date --date @1474880520
Mon Sep 26 17:02:00 CST 2016
----代码结束----

(4) 等实验完成了我才注意到,rrdtool fetch 接受一般的时间格式,还有倒退几分钟这样的功能。可以不用UNIX时间戳的。

在转换时间格式时我注意到有时区,所以为了避免可能的问题,确认了一下操作系统本地时区是东八区,北京时间。

----代码开始----
$ date -R
Mon, 26 Sep 2016 17:36:37
+0800

$ date +%z
+0800
$ date +%Z
CST
----代码结束----

5. 加强、改进,玩

大局已定,我们对手册里的其他工具做了些尝试。与其说是加强和改进实验结果,不如说像猫抓到老鼠以后行为,"总算抓到了,快让我玩会。"我在程序跑对了以后,也总喜欢再多跑两次,好像生怕它会跑出不同的结果,或者多享受几次正确地运行。

5.1 用命令行过滤数据

为了后续开发方便,我用命令行去除了数据中无用的部分。

----代码开始----
$ rrdtool fetch h3c12508_traffic_in_190.rrd -s -5min AVERAGE | tail -2 | head -1
1474879500: 1.9791172526e+08 5.0410319243e+08
----代码结束----

其中的 -s -5min 指数据截取的开始时间为从此刻回退5分钟,结束时间为此刻。

5.2. 查手册,得到解释及更丰富的语法

还有导出为xml格式

----代码开始----
$ rrdtool xport \
> --start='1474595681' \
> --end='1474595683' \
> DEF:a=h3c12508_traffic_in_190.rrd:traffic_in:AVERAGE \
> CDEF:cdefa='a,8,*' \
> XPORT:cdefa:"IN"
<?xml version="1.0" encoding="ISO-8859-1"?>

<xport>
<meta>
<start>1474596000</start>
<step>1800</step>
<end>1474596000</end>
<rows>1</rows>
<columns>1</columns>
<legend>
<entry>IN</entry>
</legend>
</meta>
<data>
<row><t>1474596000</t><v>9.0713941203e+08</v></row>
</data>
</xport>
----代码结束----

导出为json格式

----代码开始----
$ rrdtool xport \
> --start='1474595681' \
> --end='1474595683' \
> --json \
> DEF:a=h3c12508_traffic_in_190.rrd:traffic_in:AVERAGE \
> CDEF:cdefa='a,8,*' \
> XPORT:cdefa:"IN"
{ about: 'RRDtool xport JSON output',
meta: {
start: 1474596000,
step: 1800,
end: 1474596000,
legend: [
'IN'
]
},
data: [
[ 9.0713941203e+08  ]
]
}
----代码结束----

5.3. 后备方法 rrdcgi, librrd, rrddump

我们还知道些后备的方法,在当前项目中不会用到。

估计可以用于http输出的rrdcgi, 估计可以与其他语言 (C?)联合开发用的librrd,估计可以把数据库倒出来的工具rrddump。

6. 总结

猜测在学习新工具中的作用如此重要,以至于如果你没有猜测的话,就不要按下回车。哪怕你有很多种猜测也好,只要列出一张表来,一个个试过去,留下看起来最正确的那个。但是如果你没有猜测,就失去了主动性,而是被动地观察实验现象,却对支配实验现象背后的物理图景毫无察觉。

据说,李靖与李世民讨论兵法,他说: 千章万句,不出乎"致人而不致于人"而已。
hole
------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/] 悄然支持http2,再次感谢高博先生

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

读书的层次

309347656264971844我读书少,不敢妄谈读书,更不敢讨论层次。只不过还是因为读书少这个原因,想不出来别的文字,题目才取此下策。我只想讲几个故事。

1.

因为家里没有几本书,我小学三四年级的时候开始经常去市图书馆。图书馆的大部分不对少年儿童开放,只有两处除外。一处是少儿外借,以童话和科普为主,没有习题集,另一种只能在阅览室里看,花花绿绿的少儿杂志。我当时对少儿杂志颇为不屑,觉得怎么那么幼稚呢,都是大人模仿孩子说话,内容明显骗人,感觉作者以为你很弱智的样子。所以我大多数时候只读外借的那些,觉得自己很与众不同的样子。想借大人的书,不让。

这正是当今不少成年读书人的写照。就是那种感觉,我很孤独,我的观点如此帅呆,我如此卓而不群,与传说中的萨特叔本华尼采有得一拼,只是现在还没有成名罢了,你们这群盲人。也不是一样一样的,相去不远也。

现在的你当然一眼就看出来我当年的幼稚了,三四年级的孩子中的一个孩子,不过如此。

很多时候,孤独仅仅因为视野狭窄,没有找到同路人,没有看到引路人。我至今经常为想到某个观点沾沾自喜,后来发现早有人提出,而且深刻得多,完备得多。说来还是见识少。如果多些这样的打击,孤独感顿消,在古今了不起的思想中,你我的看法连渺然众矣的资格怕都没有。某些人的"祖上早已有之"也在此列,包括莱布尼兹的二进制即我周易之阴阳,包括康德的道德不就是己所不欲勿施于人么,那都是你的肤浅理解。肤浅二字,正是字面含义,不是替你自谦。
268083529194917900
2.

前一段王宝强新闻,有人提到在《唐人街探案》中早有伏笔。我怎么也想不起来,几经启发还是毫无印象。后来到douban上找剧照,才一拍脑袋,啊对对对。有些电影电视情节,看了就忘,甚至连"不好"二字的评价都没有印象。当年李记者、小刘同学大力推荐 The Big Bang Theory,我看了半集实在难以继续。后来跟Johan Lilius 教授提起这剧集,他说,不错。我说,是么,如果你推荐的话倒是值得再试一次啊。他笑着补充,看的时候记着把脑子关掉一会儿。我试了,果然灵验。如果你只保持那么几分钟的记忆 (金鱼七分钟记忆是扯淡,你喂过就知道,它们见到人影挥手就会有巴浦洛夫条件反射,决不是七分钟前训练出来的),只关注隐约的印象,不要太过于深究细节和合理性,bang,整个世界都好了,很幽默。

我用同样的方法看《破产姐妹》也很好。当年流行过的《学习的革命》《给加西亚的信》《少年派的奇幻飘流》如果我能持这样的态度,估计读起来也会顺畅很多。

但是并非所有的作品都适合这种骑马观花一样的心态,那些需要拿来真正干活儿的知识,松懈不得。可惜有些人读什么都是"在这个夏天,我度过了人生中难忘的一段,读到了如此感人的作品",除了感觉,别无其他留下。当然,还有,可以吹嘘,比如我读过《飘》《乱世佳人》《呼啸山庄》《简爱》《傲慢与偏见》《瓦尔登湖》。然后呢,这些作品的细节你还记得哪些,这些作品改变了你的什么品质和观点,能背诵一段出来也陶冶一下我的情操么?注: 我举例这些女性喜欢枚举的作品决不是男权思想,而是因为男性通常连这些都不读,甚至连篇名都不知道。

3.

当年本科一年级,大家在宿舍吹牛,不记得怎么就说到了希特勒。我就说,希特勒他不是德国人,他出生在奥地利,就像拿破仑出生在科西嘉岛,那时候科西嘉属于意大利。有人使用了群嘲技能,我被各种嘲笑。

第二天,我去图书馆借来《第三帝国的兴亡》,指着其中的某行给那位最坚定不相信我的同学看。他先是奇怪我为什么举本书给他看,然后是大度地说,"哎呀,你还这么当真啊",中间唯独没有原来如此的表情。

不少人读书是这位同学的态度,忘了就忘了,能怎么样呢。另有不少人读书 (或者读摘要)是我当时的态度,你看这个你又不知道吧。

忘了就忘了的态度,我在科幻作者中见到不止一例。参加科幻的笔会,我带着对那些作品景仰的心去的,每遇到一位作者就巴巴地说,"我读过你的某某篇,那一段太感人啦,那个人物我太喜欢啦"。好几位作者对我说,"我不记得了啊,因为我写过好几个版本,发表的时候都不知道是哪个版本了。"我信以为真,直到遇到潘海天先生。我非常心潮澎湃地对他回忆了他写的斩蛟一段场景,他很淡淡地说,"大家都是作者,你不用这样。"然后奇怪的说,"这段发表的时候删了,你在哪看到的?"我在清韵论坛上看到的。他是我见到的科幻作者中第一位记得自己写过什么的,刘慈欣先生也记得自己写过些什么。

有些作者没有忘记自己写了什么,甚至比读者记得的更多。我拜见《构建之法》作者邹欣先生,说了我在教学和工程中的一些困惑。其中有几个问题解答时他提到,就在书里的某某处作过讨论,有一处甚至引用了一下原文。面对这样的作者/读书人,我不敢奢谈我读过。因为当时还有我以前的一位学生在场,我回顾了一个故事的细节,用来说明软件工程中的沟通困难。我讲完以后,邹欣老师补充说,这个故事出自 Malcolm Gladwell。我特别担心他接着说,你哪里哪里还讲错了。你精确地记着,才能说读过了。

当年我跟 Lars 教授讨论 Applying UML and Patterns 的教学体会,他委婉地指出,如果你仔细读的话,就会注意到领域模型和分析模型不是一回事。语气坚定到我不敢辩驳,只能感谢指点,我回去再仔细看看核对一下。相信他当时就是我面对某些同学瞎说教材骗人时的感觉--你真的读过书么?站在他对面的我的感觉要好得多,谢谢赐教,令我知道自己的无知,才能进步。
824061398513530290
作为人群的分界线,除了忘了就忘了的态度,另一类是你看这个你又不知道吧,就是当初显摆知道希特勒的我的那种。摆出一大堆 (自以为) 你不知道的细节,以显示众人皆醉我独醒。比如,吾生也有涯而知也无涯 的后面还有半句,国民党在抗战正面战场中的作用被抹杀了,阿拉伯在中世纪非常发达--然后得出结论咱们都被课本害了。只有你被课本害了,不包括我。我清楚记得,你显摆的这些在课本里本来就有,吾生也有涯那段,在课本的脚注里提到了出处,还提到了后半句;抗战正面战场,我们的课本里有血战台儿庄,还配了某位将军的肖像插图,蔡廷锴和蒋光鼐的名字,在历史课本的八一宣言那节附近,不知道你学的什么课本;阿拉伯在中世纪对西方文化的保留,在奥斯曼土耳其一章里有。

另一种知识,汉字中笔画最多的是 齉,读作 nang,四声,36画,你知道么?我特别希望你回我一句,有用么。

4.

我有一次请教 Johan Lilius 教授一个性能相关的设计框架问题,该问题困惑了我不止一年。他一共回答了两点。第一点,他问我,你的显示器刷新频率是多少?我说,60Hz吧,怎么了。他说,你的程序为什么要比显示器刷新更快呢。我一拍大腿,对啊。他回答的第二点,说,"你等会"然后就开始翻笔记本电脑,过了一会给我一篇论文,说你看看就明白了。我一看,80年代的,再看内容,解决了我的困难/告诉我不必再沿此路继续。

我指着那篇文章说,老师啊,这太让人生绝望了。我想了这么多年解决不了,而1987年 (或者1986)年人家都写成论文了。他说,博士学习是这样的,你要阅读大量的文献,要了解别人做了哪些工作。我的导师牛老师和马老师也这么教导过我,只是我没有这么实践而已。

自觉站在一群俗人中间,以为自己不同于俗人,但是也只读着俗人的书,做着俗人的事,却寄希望于有超出朋侪的观点。这多么不现实。有些女性每天读着《小时代》以及诸如此类的情感糖块,幻想自己是世界的中心宇宙的未来,只等霸道总裁发现自己的美丽;有些男性读着周易、佛学、基督,长篇大论指出世界该当如何发展,如果中国/亚洲/世界按他那么整指定就好了。反正又不付出什么代价,大不了到头来一句,"啊呀我记错了"或者"肯定是你理解执行还有问题"。

如果说见识少的结果只是孤独,孤芳自赏就是另一个层次了。

5.

当年我有个学生是基督徒,她跟同学们谈起一些事迹和理论,我提醒 你某个地方可能记错了啊,补充某处如何如何。她说,老师你又不信,为什么会知道这些呢。

我当时有开玩笑的意思,"就是等着遇到像你这样信的人,然后指出你说错了啊。"

我现在有时会沉默,觉得你高兴就好。有时,我会站出来说,你别瞎扯了,你说的那些我们也知道,但还是得出了不同的结论。当我出声的时候,我想到的是邹欣、刘慈欣、潘海天、Johan Lilius、Lars 这些人。我向他们学习,像他们帮助我那样,也告诉你,1.并非所有的人都和你周围的人一样,你只是见得少;2.你可能和你周围的人并没有什么差别,得看得更仔细一些;3.你真的确信并敢于声称你读过某本书么?

仰之弥高。

有时,吾生也有涯很令人绝望,到死也读不完也读不到那种程度,活着还有什么意思;有时,想想这样也很好,还有那么多书没有读那么多道理没有懂那么多细致的义理没有参透,怎么舍得去死。
550145133099239756
------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/] 悄然换成了https,再次感谢高博先生

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

7个少根筋的笑话

1.李记者第一次跟我提他有个朋友在兰博基尼工作,我问,“那是什么玩意?”

2.被提醒去日本过海关要是有假货会被没收,我问,“有个耐克/啊迪,看价格应该是假的,是不是不行。”老师说,“这种没事,LV啥的才不行。”我又问,“LV是什么。”

3.新闻说,“不喝茅台难道喝拉菲么。”我没问就能猜到,拉菲一定是某种好酒。
img_5509
4.出差在外有人说,“现在某司存一万赠一万呐。”我困惑,“我们那儿是存一百赠一百啊。”

5.当年,我对导师说,"我想跟你学摄影行不行啊?"导师说行啊,然后开始讲各种技术,最后说,"相机最好先整台东海或者凤凰,便宜,坏了不心疼。"我问,"得多少钱呐。"他说,"一两千吧。"我马上说,"那我不学了。"后来导师送我了一台Nikon F3,我学了好几胶卷,然后珍藏着,有人想买也不卖。老外问我,你喜欢摄影啊,咋学的,我说,"用Nikon F3学的,我的第一台相机。"他表情很夸张,我想他一定认为我是富二代。

6.跟一位黎巴嫩的同学同办公室,印象里黎巴嫩总打杖,就问,"你们上一次战争是啥时候?"他说,"上周五。"

7.还是这位黎巴嫩,我问他,"你们阿拉伯人真的能娶四个媳妇么?"他笑,"你是不是觉得特别好?""没有,我就是好奇。"他大笑,"你是不是觉得特别好?""没有,我就是好奇。""哈哈,在我们那儿,你根本连一个媳妇也娶不到。""为啥?""因为你没钱。"
img_5334
8.用微博,关注了叶卡编辑强烈推荐的邹欣老师,据说很多优秀信息。结果我发现邹欣老师已经将近一年没发消息了。最近某天为了用某个APP发微博,把微博APP升级了,瞬间发现,原来邹欣老师一直在发,只是我的APP版本太低,看不到。

9. 转了同事发的照片到某群里,内容是某团队纳新,3份申请的学生们填写的计划和心愿。群里某人提醒我,上面还有姓名和电话呢,太不尊重学生隐私了吧。对啊,我赶紧把照片上面的敏感信息都涂掉,然后发到群里了。这时发现脱敏的那些原照已经不能撤销了。

以上都是真事,不是笑话,是不是很好笑。

------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

相忘于江湖

一年一度教师节,以及各种节日,同学们都要向导师表达敬意。表达敬意途径之一,是向导师献花,大家集钱买一束一篮或者一果盘,搬导师办公室去,导师好像儿女归省,很有面子的样子。

也有同事抱怨,"你看某某专业的学生啊,给每门课的老师都送了花,咱们的学生,啧啧。"还有的担心,这样的学生以后到社会上怎么能吃得开呢。我们这里文理混杂,理工科的学生相比人文类的,木讷有余,确实情商智商均低的样子。我开玩笑说,"你真想收礼物啊,那简单,你得'念央儿'。"'念央儿'我以为是东北方言,别的地方不知道怎么说,此处大体是在班级上很高兴地说,"某某届同学对我可好啦,还有谁谁和谁谁也是,给我一大筐鲜花,办公室都摆不下啦。"同事说,"我哪敢,那不得被投诉啊。"我哈哈大笑,"老师都是这样的,期待学生会有什么不同?"

除了教授知识、提供训练指导这类义务,教师对学生并无任何权利。
251159608890595519
我的导师马老师收到果篮以后,就把同学们留下,请他们把果篮搬走分吃了,然后再给补几百块钱,"你们去喝酒庆祝一下吧,我就不去了,免得你们拘束。"

我的导师牛老师讲过另一个故事,差不多的寓意。他去芬兰的时候,合作的教授阿里依瓦斯卡亲自开车接机。牛老师说,"派你的学生来不就行了嘛。"阿里教授说,"他们是我的学生,接你是私事,我没有权利让他们做。"

牛老师讲这个故事的时候,我还没有毕业,并且从此开始领教每次吃饭只有导师可以付钱。毕业以后终于一次有机会我来请客,而且事先说好了,临期末了导师又要执意他买单。我急了,说,"这顿你要是不让我请,今天我就不吃了/以后永远不和你吃饭了。"这才得逞。

我本科的导师李老师教导过我,如果你收了学生的礼物,学生心里就会看不起你。

我的导师们都是这么做并且这么教导我的,我也尽力模仿。按中国的习俗,如果我对学生们说,"你们千万别给我送礼啊",这就会被理解为鼓励甚至督促。所以我演示。当偶有同学送我东西时,我一概问明价格,"因为买礼物送给你需要花时间,你又不一定喜欢,真是困扰我,所以我原价照付。"如果你不告诉我价格,我只好搜索,然后估算。凡是领毕业证之前,哪怕一天,我们都是师生,这一点你就只好服从我。

毕业以后的学生,我也极少跟任何其他同学提到他们送过我什么。事实上有不少,如果我一直不说,你们可能会以为严苛的老师同学们一定记恨一生。计有明信片,咖啡、杯子、勺子,印章,各种坚果,刚毕业时花大价钱买的我现在还没有穷尽玩法的玩具,花束,诸如此类的,亲自送来或者快递。

我之所以极少提到,是有原因的。当你鼓励的时候就是评价,即使正面评价的时候也一定包含对不同行为的贬低。佛教徒说,我本人不吃肉,我并不反对你吃肉,不过你修行到一定程度的时候,一定就不吃了。合理的推论就是: 你的修行不够,吃素是更好的,因此你不是"更好"的。所以,大张旗鼓地宣传学生对导师如何好,无异于鼓励这种行为,并否定其他同学。前几天我偶然提到某以前的学生送我啥啥之后的故事,一位没毕业的同学就私聊微信提到,限于我的规则所以啥也不能送我,只好努力干活云云。L哥,我讲那个故事的重点完全是后半截的情节,你心思太重了也。

我不期待跟你们建立任何超出知识和经验传递以外的关系,所有后来结下的情份都是我们一起战斗互相战斗产生的战斗友谊。仅仅这样,已经很好。我不希望你我之间产生任何人身依附,只有同生共死才能有人身依附,而你承担不了与我生死与共的负担。超出知识和经验传递以外的关系,这也包括没有能力向你提供道德训诫和演示。
412470264993999120
前几天读到的一个小故事,作者说,流浪猫送给喂他食物的人一些小猎物,老鼠、鸟、兔子,并不是认为"人类太笨,不能养活自己",而是对他的爱--基督教意义中的爱你的邻人和爱你的亲人的相同的那种爱。这种爱就像两个侠客在江湖行走,偶尔小聚喝杯淡酒,聊聊人生和别后的际遇,比比剑法,然后"'今番良晤,豪兴不浅,他日江湖相逢,再当杯酒言欢,咱们就此别过。'"没有虚假的思念,也没有"有时间喝酒啊""一定一定",能相聚时自然相聚。

我希望,咱们就是这样,相忘于江湖。

------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

一起涂墙吧,没有艺术细胞我们还有工程思想

并非所有涂在墙上的画都能有资格被称为壁画吧。咖啡厅墙上黑色勾边颜色鲜艳的脸谱、地铁施工现场的隔离铁皮上的宣传画、城中村变压器下水渍浸透的鬼画符一样的涂鸦。恩,还有我们小时候写在地上的"天下太平",写在墙上的某某某(此处删除若干不文明用语)。

我们自己在墙上画的也不能算作壁画吧,没有足够的艺术修养,勉强靠理工科思维的帮助成型,所以估且称为涂墙。我和女儿花了6次大约10个小时,在客厅兼餐厅的墙上涂了一片白桦林,幅面 130cm*230cm。

我并不无美术修养,只是希望借此让孩子感受到: 追求的过程,这一过程本身就是全部。我经常读到名人传记 (包括不限于伯努利、各种四世三公、贵族需要三代才能形成)中提到,因为父亲母亲祖父的影响,某人遂有今日。如果没有父亲母亲祖父的影响,后果不堪设想。想想吧,连伟大导师马克思的妻子燕昵都是流着蓝色血液的普鲁贵族的后代。我想告诉女儿,目前的现状就是这样,她的爸爸不幸并非画家,没有能力引领所有她渴望的梦想,不过我们可以想点别的办法。

写这些也想告诉你,没有什么是必不可缺的,没有任何基础也不重要,一切都不能阻止你想疯狂的心。在你家墙上画一幅大画吧,完成以后--心情愉悦,自信满满,睥睨天下。松田道雄在《育儿百科》中说,不要在乎你的孩子在墙上的涂鸦,不要责怪他,你的房子不会因为墙上的画而减价的。是的,因为下一任房主一定会重新粉刷。

还没有下定决心么?我最初也没有这样的勇气,直到一个契机。

因为担心太聚精会神导致手掌穿透书柜的玻璃门,所以我们在上面粘了不少"静电贴",是深绿色各种形态的藤蔓。效果不佳,显得很暗,因为静电贴是设计来粘在白墙上的。粘在白墙上以后,我又发现,以前的学生Grain同学送的数字油画还剩不少颜料。于是我和二猫在征得二猫妈同意以后 (这是一个必要步骤,切切),临摹静电贴在墙上画了一小块,80cm*40cm。
2 铅笔打稿,共同填色,研讨绘画技术和艺术效果,这些让我和二猫分外团结起来。我们决定,在墙上搞个大的作品! 白桦树是几天讨论以后确定的第一步,下一步是在遥远的未来,画一棵从地面到天花板的圣诞树,树尖上站着一只《冰河世纪》里的松鼠,手里拿着一颗栗子。

我们为此观摩了邻居咖啡厅里的墙画,我解释了勾边的困难,并预想了勾边失败的可怕后果--一面糊面颜料的墙,色块犬牙交错,惨不忍睹。

工程思想1 先解决风险最高、最困难、后果最严重的那个 use case。如果不能解决,那么尽早结束,甚至不要开始。

解决方案是前一段时间在图书馆参加刀笔画协会的培训班时学的。胶带。把胶带粘在画布上,涂色,大胆涂,颜料干了以后把胶带揭掉,就留下整齐的边缘。

核心技术原型完成,真正的施工 (而不是艺术创作)开始了。

1. 寻找参考

二猫用PAD在网上一顿找,找各种白桦树林。有的,是实景照片,颜色过于丰富,而我们没有抽象能力;有的,虽然卡通,但是有渐变的颜色,这个技术上不知道如何实现;有的丑,有的她认为丑,有的我认为丑,有的二猫妈认为丑……

后来我们把一幅卡通风格的改了。决定用白墙作为"阴形"来表现白桦树的枝干,在白色上涂白桦树皮揭起的特殊纹理,而背景涂满天空的蓝。并且蓝色不涂满,做成百叶窗的效果。

嗯,还有草地。还有桦树主干要做成粗细不一远近不同。

工程思想2 时间是不存在的,是静态的。从最初,我们就应该知道未来全部的样子,整个经过,每一步的后果。

还有,要有充分的心理准备。二猫说,"你能接受很多天墙上画满了草稿么?"铅笔的、完成了一半的。完成一半,不是左半边右半边,或者上半边下半边,而是每次几种颜色,景物逐渐显露出来,变成它们本身的样子,最初是天空,后来是远方,后来是白桦的斑纹,草地,和初春的叶子。

2. 手绘小样

把心中的样子按比例、形貌、色彩画在纸上。

工程思想3 谋而后动。没有设计就没有代码。如果是代码帮助你认清了设计,那么,你在进步,或者说,你原本并没有足够成熟。

我告诉二猫,你能想像么,这幅小画放大以后在墙上的样子。你是不是喜欢那个样子,现在修改还很容易,一旦我们动笔,就万难更改啦。
4
3. 铅笔稿,第1次上墙,1小时

估算好位置,大致与小样对应,在墙上打铅笔稿。不必担心铅笔的印记影响以后的效果,"壁画"是在远处欣赏的,远处看不到铅笔稿。

铅笔稿一定,我们就只剩下了填色这样的局部工作。虽然每一步我们都要回归到头来审查当前的实现是否符合设计的全局,但是全局的样貌在此刻就已冻结。全局确定以后,每一次迭代施工,就只需关心局部。一个优秀的项目负责人,不应该对属下说,"你们多考虑一下全局",这是将军的责任,不应推诿给士兵。

我用一米长的曲尺帮助打铅笔稿,二猫站在后面远一点的一方帮我看是否垂直和平行。没错,曲尺和墙角足够确定垂直和平行,不过二猫参与得格外有热情,而且,她确实纠正了我几处显然的错误--站在墙前画线的人看不到,而远处全局却能一眼发现。

有人提到可以用投影仪帮助,把要画的图投在墙上,我没有试过,想来应该有效。

4. 天空,上墙计3次,每次1小时至1.5小时

准备今天要涂的颜色,调料盘是剪开的速溶咖啡盒子。

胶带粘在*不想*涂到的地方。不要吝惜胶带,30米三四元钱。把所有今天要涂的面积里不需要的地方粘满,这样画的时候轻松很多。永远不要在设计和准备的时候假设自己将是个聪明人,而应该假设随后施工的是另一个人,你有向他交待的工夫,不如把不希望他做的路都堵死。

胶带粘好以后,拍照留念。每一步都拍照,用于回顾、检讨、吵架之用。嗯,开发和工程的时候我们是这样的,涂墙时这么做纯是爱好……或者习惯。

胶带已备,大胆涂墙。不必担心涂到边界以外,甚至可以特意涂到胶带上,以保证边缘的地方没有涂漏。

涂完以后,拍照留念。然后不要手欠去揭胶带,会把丙烯一起像布一样揭下来。等明天就可以,当当,揭幕一样的感觉。先前模糊的边缘,烂糟的涂鸦一下子就清晰起来。

天空有三种蓝,所以分别涂了三次,算上胶带时间,每次都1个多小时。
6

7

8
5. 白桦树1次,2小时

其实在涂天空的时候,因为白桦的枝干有意留白了下来,作用阴形,白桦的轮廓已经完成了。枝干细小,如果对刷子用得不够自信,也可以把枝干粘上胶带再涂周围的天空。

白桦树的斑纹一共5种颜色,除了白色以外,是4种 黄或者褐。每选定一种颜色,我持刷子在凳子上面壁站定,用刷子虚指遍历墙上的铅笔稿斑纹闭合回区域,二猫站在后面远处指挥我,"这个涂,这个不涂,这个涂,这个不涂,刚刚那个涂上好看。"凡是涂的,我用刷子点一下作个记号,然后大家冲上去用同一种颜色覆盖,泛洪算法。涂完这种颜色,再选一种颜色重复这个过程。

这个时候,我们看到了白桦树在蓝色的天空之下显现出来。
9
6. 草地和叶子 1次,1小时

草地也有3种绿色,跟天空的色彩一样丰富,不过有了以前的经验,我们一次就完成了。

胶带,涂各种绿色。没有枝干,更加容易。涂草的时候,我突然福至心灵,在白桦上点了一下,嫩的叶子。二猫也兴奋地爬上凳子,这点点,那画画,白桦林从晚秋到了初春。

在白桦林中用餐,又浪漫又文艺。吃饭的时候,我们常常自恋地赞叹自己的作品,二猫觉得我是个英雄。很多年以后,她可能根本不再记得我原本的希望,就是虽然没有画家爸爸也可以想别的办法涂墙,但是她不会忘记这片白桦林,比我们还高还宽的白桦林。我还期待这片白桦林是一颗种在她心里的种子,她会更勇敢地生活,会在心里暗暗质疑和思考很多事,"为什么不可以",她会回想起很多人甚至没有胆量在墙角偷偷画上一只小鸟,而她在小时候就涂满了整面墙壁。
10
------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

继续背单词,8个月过去了

8个月前,我在用百词斩背单词。当时背了49天,完成了托福、托福核心、GRE3000几本书,单词量测试从5000~8000上升到11000左右。向大家推荐[https://zhuanlan.zhihu.com/p/20468330?refer=younggift]了百词斩以后,我没有停止,而是继续背单词。

现在,我使用百词斩背了230天,8个月前的时间消耗只是至今的五分之一。之后我还使用 扇贝 背单词,一个更严厉 (反复复习考核、进度更缓慢) 和没有图片和视频的 (有声音)的不幽默的APP。使用扇贝至今188天,也远过了8个月前的持续49天,那时我觉得49天已经很是漫长。
439853597373071395

725732918178518183
只是那个时候还没有想到,49天之后有更加漫长的历程。我想起小学时读过的一段文字,说一位日本作家患了癌症,还有一年半的生命,写了本书叫做《一年有半》。有人说只有这么短的生命还写什么书,难道不应该去享受人生么。这位作家说,与无限长的死亡相比,有限的人的生命无论多么漫长也只是一瞬。我们感觉到的此刻的漫长,不过是因为还没有见到更漫长的所在。

百词斩因为进度太快,背完托福以后进入GRE,很多单词是我从来没见过的,维持速度的结果是记得不牢,等复习和测试的时候学习效果非常糟糕。1月1日完成GRE这本书的学习以后,为了巩固我设置了30天复习,结束以后又设置了30天、100天复习。每一次,我都在想,30天、100天,这么长,啥时候能整完呐。类似的,为了精细点学习,我开始 扇贝,那是2月4日。每天只能学习150个单词,其中新词25个,预计结束学习时间是7月28日。在1月1日看100多天,在2月4日时看7月28日,非常遥远。最终这些漫长的时间都已经过去了。

前些天开会,巧遇出国英语培训的高老师。我兴奋地报告,"老师我向您汇报一下,我背单词现在测单词量达到1万8啦,我背新概念第二册……",老师接着说,"全背完啦?"我说,"没有,背了从55课到92课啦。"老师说,"现在是还有出国机会是吧?"我同保持着兴奋响亮地回答说,"没有。"

不是为了现世的功利,只是补课以前落下的作业。以前看到有人说,GRE单词并不是什么高大上,而是英美的严肃日常中经常出现的词汇,我没有信;以前看英文小说的时候,跳过大段的景物或人物服饰或对话,觉得无聊 (中文小说我并不会跳过)。当背单词到某个阶段的时候,渐渐发现,小说和严肃课本中,都经常现出GRE词汇,GRE词汇就是常用词汇,渐渐发现,那些我跳过的内容,正是文章的精华之不可或缺的部分。

有时候我会感觉非常后悔,如果当年更努力一些,早一些拥有现在的词汇量,应该可以看到多少错过的风景。人生苦短,早些开始,早些受益。

我现在所花费的200多天,是我的一些同学当年就已经花费过的--而且不会短很多。在2月初看到7月末的时候,我被这么多个月震惊了,那就是从寒假看到暑假了啊。如果我被那时的漫长天数吓住没有开始,此刻,也还会有200多天在等着我。
281771869616657326
总天数是降不下来的。如果降总天数,只有提高每天的工作量。每天一组百词斩然后150个单词扇贝的工作量并不小,有相当一段时间,我每天要花费1个小时。再增加时间,不是身体吃不消,就是老板们要愤怒。事实上,我见过同学们通过四级六级研究生英语,他们也都花费了100天或者几百天。在这么漫长的时间段里,就像马拉松一样,我甚至失去了突击的兴趣。有那么几天,我一天背下几天的单词量,然后在接下来的几天发现很快又忘记了,所以突击毫无值价。记忆和遗忘的规律限制我,突击无益,只有稳定而缓慢地前进。更重要的是,想想还有一二百天,突击这么三五天,又有什么意义,毕竟没有能力就这么一路突击下去。这种突击我甚至进行了好几次,每次兴致勃勃地开始最后灰心丧气地结束。但是这也没有什么负面影响,和三位数的天数相比,那些失败的尝试也只是战斗的伤疤,并带不来致命的影响。和漫长的时间相比,任何短期的成败在全局中都影响甚微。唯一影响巨大的,就是持续的时间。

在这段时间里,我也有过很多次动摇。我经常在夜深人静的时候,背完马上开始的这个今天的份额,然后开始质疑自己的动机和意义,"我这是图的什么呢?我多大多大年龄了,我再也不需要英语考试了,我有诸多理由不做这件事。"我安慰自己,如果此刻不背单词,就有更头疼更难办的任务等着。没错,另外一些甚至不知道如何开始的任务的压力是我开始并保持背单词的重要原因。我安慰自己,期待单词量2万的那天,期待 扇贝承诺的,开启看另一个世界的眼睛的时刻。我安慰自己,反正今天还剩3/4就背完了,还有1/3,还有20个。我发现自己醒过来,手指无意识地划错了好几个单词,刚刚睡着了,然后我靠在椅背上把一条腿直腿抬起,让自己更清醒一些,然后开始背下一组。249428053735204532并不是有意想折磨自己,如果不是午夜开始,白天之繁忙可能让我根本没有时间背单词吧。

最令人沮丧的并不是时间的消耗,而是成绩上升之缓慢。百词斩GRE3000那本书刚结束的时候,每次测试100个单词,我能错到20多个,1/5。而且错误率长期居高不下,长期有多长,我已发不记得了。后来,错16个,保持了又很长时间,突然有一天,开始下降到错10个以下。然后反复,错多些,错少些。现在,每100个错5个左右,并且保持稳定了。

测试单词量也不停地波动。在百词斩里,可能由于算法调整,也可能是结果就应该不是非常稳定,单词里在1万以上以后就往复波动,从1万2到1万6来回调制我的喜忧,后来终于稳定地开始上升,1万2,1万4。
475953298344451274
单词量测试一直在波动上升,不波动而是稳定变化的,是每天消耗时间的下降。因为错的数量慢慢变少,因为点击的信心越来越足,从最初的1小时到半小时,到后来十几分钟就能结束战斗。

单词量追求的目标是扇贝的2万。扇贝最初的测试,因为有百词斩的基础,虽然GRE如此糟烂,但单词量已经1万,有个1万词汇的奖牌。下一个此类奖牌就是2万。背完 扇贝 的GRE巴朗词表 以后,我隔几天就测一次单词量,有时候全对了,单词量也只有1万8多一点,可能随机出现的词汇难度和覆盖范围不同吧。我期待着终于有一天,"嘭"的一声,2万的奖牌就到手了。很多次,快测试结束的时候误操作错了一个。很多次,心跳加速得控制呼吸,又在最后关头出来个从来没见过的单词。很多次,全对,18500,19500,我大叫"你耍赖"。非常平静地又是一次全对,2万,系统送了奖牌。但是我已经不再为奖牌激动了,我得到了更可贵的。
865106733758962013
当我在百词斩和扇贝里看到另一个APP中刚好背过的单词,当我在 冰与火之歌,在 幸福之路,在 Rework,在 Conqueror of the Seas,在诸多教科书里看到那些"刚刚"背完的单词,当我看到有些似乎眼熟,确切意思想不起来,查下词典,"啊,原来是你",这种感觉就像看到多年未见的老友远隔重洋打来电话,然后我一下听出他的声音。

此生共渡,你是不是偶然也感慨,如果早些相识多些珍惜,就更好了。
371946024317289427
------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

书是进入另一个世界的门径(2)--5篇短书评

1. 编程格调

原著书名为 The Elements of of Programming Style, 胆敢取名 elements 的书还可以一版再版的,都牛得不得了,比如《几何原本》。此书与《几何原本》从几条简单原理推导出整个世界类似,给出若干来自实践的原则和原则应用的案例,如何应用还得你我在实践中参详,像习题集。对于计算机专业短短的历史,这些原则非常古老,书成于FORTRAN流行的时代。但是真正本质的原则往往从行业诞生之日就隐约存在,并不需世事变迁而有所损益,只是等待时间雕琢慢慢让它们清晰起来。比如C语言的成功并不像课本前言中写得那么轻易和简单,超越同时代诸多竞争语言赢得声名和后继影响决非偶然。本书作者之一即是C语言和UNIX创造者之一。
IMG_1064
2. 探索幸福的人--苏格拉底传

最初他是牧羊少年,跟从导师膜拜太阳,观察父亲雕刻,亲近美丽的恋人,与年轻友人终日游乐。希波战争,他披甲从军为城邦杀敌。战事既毕,父母双亡恋人嫁作他人妇。他终日沉思而无所得。后来,他学习母亲成为智慧的助产师,为伯利克里用父亲的刻刀完成凯旋门上的三女神,形象分别来自舞蹈的快乐的悲伤的同一个人。后来,他和身为僭主的学生斗争,后又因学生而起受审死刑。在判决以后等待行刑的篇章里,我虽然早知结局竟也心存侥幸,期待前往克里特岛的船不能如约而归,用阿波罗的神喻推翻人世的裁决。然后苏格拉底嘲笑所有的愚蠢,也嘲笑我,他说死不过是另一个开始,他说我所关心和引述的所有时间线都不重要,世俗以外的那部分才是真正地活过。

3. 抚顺故事集、民国了、心殇:我在伪满洲国读书的日子、匠人

《民国了》讲的是民国以前的人物,讲的是导致满清覆灭民国形成的昏乱大势中的群像,投机的、争利的、夺权的、有勇无谋的、无组织无纪律的,世无英雄竖子成名。其间鳞光片羽的几位旁观NPC的头旁写着醒目的名字: 陈独秀、毛泽东、蒋介石、叶圣陶。所以这是一部前传么?《抚顺故事集》讲的不是这座东北城市,而是城中的人,所以是《呼兰河传》;《匠人》讲的不是工匠精神,而是身为这些职业或随便什么职业的人,所以是另一部《一个一个人》。《心殇》讲的是关内少年在东北日满时期所见的蛮横的校长、亲切的邮局姐姐、马场割草的兵士,还有影响至深的老师。他是优秀的学生,只知有日满不知有中国。高中即将毕业满心向往留日学习时,东北光复。大潮之下,众生皆是沙砾。大潮之下,看群书对世事人物的怜悯、诅咒、白描,猜测作者的意境,也许可以暂缓苦痛?

4. 信息简史,人类群星闪耀时

《信息简史》断断续续读了超过一整年,每次出差旅行都随身携带,然后郑重推荐给zhumao看。还记得在东汤温泉,靠在床上,虫鸣不断,有几个孩子笑叫,手边咖啡,眼前正读的是《信息简史》,触手可及的是《人类群星闪耀时》。就像有一些流行歌曲或小说人物嵌入在你的成长道路上,以后每当你听到这段旋律,看到这个名字,它们都不仅仅是别人所见的那些,而是背后整整十年的青春岁月,是你的爱和怅然。是你强忍着没有流下来的泪水。这两本书揭示那些事件、定理背后的意义。《人类群星闪耀时》讲述历史课本上的重要事件,关注事件背后人类的光辉;《信息简史》讲述那些今天看来如此显然和正确的定理诞生时的艰难,把信息论的脉络隐隐地埋在我对“万一错失良机没有发现”这样担心的故事之中。

5. Conqueror of the Seas

如果我来翻译,会定名为《征服众海》。汉语中有群山、众山,而海则不同,最多只有四海,那已经是天下一统的代名词。麦哲伦征服了一众海洋,大西洋的风暴、加勒比海的热情、南美沿岸的丛林、亚马逊河以南每一个河口和港湾、幽暗如地狱之门的麦哲伦海峡、平静冗长危险的太平洋、还有他在远征开始以前就已征战过的印度洋、印度尼西亚群岛,传说中的香料群岛。伴随他的,不止是地理名词,大地和海洋从来不会毫无代价地就低头臣服。他背叛了国王和祖国,他杀死了背叛和试图背叛的船长,他最初计算错误而后欺骗舰队"海峡就在前方,不远就是终点",他忍受着腐肉和溲水,他面无表情从不征求船长们的意见,下令"向前向前"。船员出发时265人,归来时18人,他本人命丧为西班牙夺取岛屿的战役,被他铁链锁住5个月的一名叛军继续下面的任务。他用生命换来的岛屿后来卖给了他宁死也不回去的葡萄牙。跟他一起环球的奴隶没有按遗嘱解放而是被残酷对待所以策划土著突袭,击杀了绝大多数优秀将领。按他的意愿应成为世代总督的孩子一个早殇一个流产,他的妻子在他出发后一年去世,又过了两年,他的船队归来,没有带回他的尸体,而他希望安葬在海港的教堂。环球航行,五艘巨舰仅剩其一。很多吨食物和工具换成了很多吨香料,这就是全部么,交换和利益?这不是全部,甚至不是征服众海的意义所在。生的意义,在于航向人类所未知的领域,死的意义也是。
IMG_1638
---------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

回望来时的路:构建之法 东北师大站 2016春季学期

1. 前因

微软邹欣老师著有《构建之法:现代软件工程》[https://book.douban.com/subject/26577755/]。第一版首版以前,我还不知道邹老师是哪一位,就在网上曾经看到过有人转引他的观点,感到说得太有道理了,一拍大腿的感觉。比如他提到教师和学生之间应该是健身教练和学员间的关系,不是教师带领学生参观浏览,也不是狱警和囚徒的关系。比如他批评没有代码量的软件工程教学。《构建之法》到手,第一遍粗读我花了一周的时间,酣畅淋漓。很多处让你再拍大腿,“对啊,这正是问题的症结,他的招儿没准好使呐。”在那以后向我的好几位学生极力推荐阅读。似乎亮哥看了,别的同学也没有怎么重视,虽然我极少推荐读哪本书,怕推荐多就不值钱了。

book

邹欣老师本人是微软首席研发经理,北大、清华、北航等采用过《构建之法》作为教材。一方面权威,另一方面也令我等小校望而胆怯。有次在周筠编辑的群中得知,他有意图促进《构建之法》和“learning by doing”的软件工程教学理念在不那么特别好的学校里推广,顿时心向往之。我想起不少小说里描写到的文革时期随便那么几个主人公小青年,就能懂副歌,能关起门来讨论伏尔泰和卢梭。时代之进步,让我们有机会偏居一隅而能与世界对话,应该充分享受比那时更幸运的条件。但是那个学期我排课程失败了。邹欣老师后来招募远程助教参与别的学校的教学,我也非常也申请,但是估计自己的时间和精力不足以做出工作量的承诺,只好放弃,非常可惜了很久。

本学期有机会开设课程《软件项目管理》,赶紧求同学们选我选我选我,达到限额,终于开课。

2. 课程的一些数据

2016年3月4日13:30:00计算机楼320教室,夏一鸣同学[http://www.cnblogs.com/xiaym896/]在他最后一篇技术博客里清楚地回忆起时间地点。事实上,他回忆错了,第一堂课因为排课冲突,临时改到了二楼的微格教室,以后的课程都是在320教室,不过时间没有错。

3月4日起,课程教学持续12周。

选课时间注册XX位同学。这个数量并不重要,仅为超过开课人数限制。这里有些同学根本不打算要成绩和学分,只是助我开课。感谢。

实际参加21位同学,坚持到结束17人。放弃的同学,有的是在第一次课程以后就发邮件通知我了,只要成绩,不想参加项目实践;也有同学尝试了开设博客这一步,然后放弃;也有同学比这还努力稍多一些,发了一两篇博客。鸡汤名言说: 所以的失败都有一个共同点,就是坚持的不够久。也许我们所能直接看到的利益太少,也许我们能够做出的选择太多,也许如刘伟硕同学说,缺乏强制措施。还有同学在学期末的感言中提到,如果能够再有一次机会,如果可以重开此课,诸如此类。说实话,今生放手的人,我不怎么相信来生会更珍惜。

这17位坚持到底的同学中,有三位旁听生。他们没有注册,也不会有学分,但是成绩优秀。其中一位是我以前的学生,她现在本人也是教师,同时作为邹欣老师本学期某校的远程助教,名郑蕊;一位是现在的研究生,但是他没有选课,名亮哥;一位是本科三年级同学,名冉华,他曾经一度参与亮哥的项目。郑蕊和亮哥的成绩属最优秀的之列,冉华同学独立完成了一个持续10天计累计46.05小时的小项目《H3C汇聚层交换机认证在线人数展示系统》。这告诉我们人的主观意愿和追随内心的力量。

全体同学发布技术博客共254篇,人均超过每周1篇。教师发布21篇,每周约2篇,其中一篇是这一周作业重点提示及更新点评,另一篇是这一周作业的成绩。

在第3周开始,全体同学结成4个团队,每组约4位同学。其中3个团队站到最后,1个团队在alpha发布后开始解体。解体的团队,有1位同学加入其他团队,另2位同学保持游离态。

以团队为单位发布项目,学期末发布共5个共3种。3种项目是 抢答器、记账本、四则运算在线,分别源于耐撕团队、OneZero团队、爆打团队。在学期中真beta版发布后由每个团队选择fork其他团队的一个项目,并在两周内增加功能,与源出的团队竞争开发,即要求每个团队最终发布2个项目。学期末,抢答器、记账本有2个团队分别发布branch,四则运算在线1个branch,共计5个。这样做教学上的原因是东北师大北前没有积累可供训练 维护 阶段的代码,以fork其他团队来部分贯彻邹欣老师提到的:写一万行代码,在别人的十万行代码中愉快的运行。

所有的技术博客和代码可以通过教师博客[http://www.cnblogs.com/younggift/]找到。

在第2周课程的时候郑蕊同学建立了 东师软件工程 微信群。不过与《构建之法》其他高校的群不同的,东北师大的群里基本没有人说话,教师临时修改增加作业或点评,也不太有响应。我本人不喜欢在“群”里被集体通知或告之,然后自己选择是否与自己有关。这种被组织的感觉不好。我担心同学们是这样感受的,进而进入 狱警囚徒模式,所以对群里一片安静听之任之。东北师大的群最后大家选择了实名(而且人数这么少很容易人肉出来吧),据说有的高校的群是匿名的,有同学发表了对教师和/或助教的不满。这也是个大家不吱声的原因吧。还有,可能由于就业太容易,似乎无论什么对就业都没有什么正面或负面影响,东北师大的同学似乎历来高冷……我习惯了。

3. 历程

第1周和第2周,基础知识及鸡汤。知识不是重要的部分,更不用说对于研究生阶段的同学。往往是,我们知道,但是不做。更重要的,猛灌鸡汤。同学们通常并无强烈的动机想进修软件工程。他们的热情一般止于热烈的表达愿望,或者言不由衷地对科目重要性的认识,有时还有对教师的表扬。但是,也仅止于此。第一轮工作量就会把他们貌似熊熊燃烧的小火苗烧熄,然后他们会说,“其实也那么重要,其实也没那么渴望”,用那么二字这一程度副词否定自己的“初心”当真是好借口。鸡汤是药,不能停。在真beta发布前后,教师说,以后不会再有鸡汤了。那个时候,同学们疲于应对从没见过那么多的工作量。同时,教师对同学们不能甚至消极地响应很失望,邹欣老师和周筠编辑的鸡汤也不足以补足元气,对每周的截止时间周三晚24点守岁般度过然后你没有提交作业很失望。我觉得,你们并不像你们所声称的那样希望我们共同所做的事,而你们没有想到我会坚守承诺,并且对你没有坚守承诺愤慨和绝望。我就是在这个时候放弃的,当你用行动宣布放弃的时候。好多年前我用更激烈的措辞给学生们写过一封信,大意是,我们不是因为情感走到一起,而是因为共同的目的,你不坚持,就是背叛,我绝不挽留。我现在会微笑着对全班同学说,“我爱你们,同学们,发自内心,而且你们真的与以往每届都如此不同”。不过,我没有什么不同。

从第3周开始,分团队,团队项目立项介绍。两周SCRUM,要求每天站立会议及会议报告作为技术博客,每个团队共10篇。不过这只是要求和愿望。不少同学们在这时还没有意识到我在第一堂课的鸡汤,“刚工作的同学往往以为有60分这一档,其实那是不存在的,工作上只有0分或及格。”只要你有一点不符合要求,就触碰了底线,0分。超过截止日期,要求的项目有没有完成的,指标达不到要求的,要求结对没做的,要求互评不评的,都是0分差评。在工作中,我们就是这样一步步失去信任的,如果偶有错误,时机不定;也是这样一步步赢得信任的,如果你每一次都符合要求。有同学问我,在工作中如果做得不好,是不是就会挨批啊。不会的,成熟的上级从来不批评你,只会减少你的工作量,越来越少,直到转岗开除。而干的好的,会不停地挨批要求改正要求更好,然后升职,去承担更重要更可怕的工作。

两周SCRUM后,alpha发布发期进行。此前亮哥创造性地给了一个发布剧透,介绍发布时将会发布的事情,简述功能。此后,剧透成要标准要求。alpha发布后,每组有1位同学离开原组,加入新的团队。alpha要求有真实用户评论,4组团队只有2个用户评论,并不详细和认真。达不到要求,和教师不敢于认真要求,都是一步步的,如同腐烂,是缓慢开始的。有一整天不呼吸,以后就不能呼吸了,有一年不联系老友,他就不再是老友了,有一次不遵循规则超过要求,以后就不再是完美实现了—不少人就此放弃,虽然不完美也比一次次放弃要强。

东北师大的SCRIM及alpha早于《构建之法》16周的教学计划,是因为考虑到课时少,可能会早于16周结束,另外假设学生有更好的软件工程课程基础,因此理论教学减量。

alpha发布如同《构建之法》其他高校及邹欣老师的预料(通常总是如此),同学们高估自己可能输出的工作量,有太大的雄心壮志,然而无能实现。所以alpha发布后,同学们都趋向现实和保守,每周只肯实现一两个工作量不大的功能,我甚至怀疑大家开始降低投入时间了。

4周已过的时候,颁发领跑衫两件,奖给当时成绩最突出的两位同学。分别是郑蕊和刘伟硕[http://www.cnblogs.com/younggift/p/5352171.html]。zhengrui

liuweishuo又两周SCRUM,每天站立会议及报告,然后beta发布。在这两周中也包括对alpha发布的review。考虑到研究生同学有更自由的时间可供支配,此处比《构建之法》减少一周专门的alpha回顾。这两周SCRUM之后原计划是beta发布,但是各团队并未做到beta的应有之意“公测”,没有真正用户,并且功能也并不大的进展。

教师称此次发布伪beta发布(因为没有真用户),要求再两周SCRUM,增加功能找真用户,然后真beta发布。这期间教师按学校要求出差1.5周,在网上看了作业,但是由于视力原因不能点评,真beta发布由亮哥主持。在此期间郑蕊提到有一周的工作状态是“失控”,其他同学虽然没有提到,教师以为这是普遍的现象。同学们开始痛恨或者无视课程要求,工作量压得喘不过气,并且维护既有代码并增加功能带来更大的压力。虽然各位在学期末的回顾中很享受的样子,我深以为有多半是军训般的斯德哥尔摩效应。我们不应该喜欢训练带来的痛苦,我们只是喜欢训练带来的结果。之所以如此痛苦,是因为以前的积累太差了—像网上的段子说的,期末的突击学习的难度,取决于你是复习还是预习。在这样一门课程中,又要积累编程经验,又要学习工程理论,又要实践。恩,既然贵族需要三代能积累出来,那么我们还是继续做奴仆好了。

第12周期末final发布。要求所有需要成绩的同学参加,本学期唯一不接受请假的一天。有同学电话我了,确实有非常之理由需要缺习,我表达了我的理解,也请他理解我不能接受请假的理由。

在final发布时,又颁发4件领跑黄衫,分别奖给
特别能作战 齐嘉亮[http://www.cnblogs.com/dendroaspis-polylepis/p/5534847.html]、
敬业福 夏一鸣[http://www.cnblogs.com/xiaym896/p/5536226.html]、
可以托付靠谱 濮成林[http://www.cnblogs.com/charliePU/p/5537734.html]、
力挽狂澜 高鑫[http://www.cnblogs.com/gaolzzxin/p/5515451.html]。

qijialiang

xiayiming

puchenglin

gaoxin成绩核算,需要按学校的要求,作业和期末论文都要交纸质品。具体的我要求为技术博客打印,期末论文打印,代码我折衷了一下,给出代码片断及下载地址。

最后,进入邹欣老师所说的“诸葛亮会议”时间,会团队review,教师也review。在此期间以前的毕业生正在上海工作的李暘发来对耐撕团队代码的review,使本已沉寂的耐撕团队队员内心又起波澜。课程有结束之日,求索没有停止之时;常回望来时路,才能进步。

meeting

4. 外援

邹欣老师拿出自己的稿费征募远程助教,为各高校提供帮助。这样一门实践不瘸腿,代码量和写作工作量很大的课程,需要助教给学生及时和充分的反馈才能得以进行,而高校机制决定难以实施。邹欣老师自掏腰包,以及课程本身的吸引力,颇有一些实践经验丰富的工程师承担了助教工作。助教无疑也付出了非常多的时间,要知道,几乎每一行代码、每一行文字,助教都是审核过的。只是,也许能力,也许精力,更重要的是时机,助教没有指出学生每一个细节的失误。我本学期没有申请助教协助,因为知道成绩核算方法和教学水平都不一定能保证满足邹欣老师的设计意图,所以由我一个人兼作教师和助教。从我的学生仅17人计,仍然感觉工作量非常大。我最初每次回复和点评技术博客,需要1至2小时。后来只好拆分成几段,挑空闲时间而且有PC机的时候处理。很多个小时,一般是一整个下午,多半个晚上。牛宝乐老师和郑蕊老师分别做过助教,他们也都提到工作量巨大。我知道承担助教工作的还有幻飞龙博士。虽然我没有申请助教,但是也从助教群中收获不少,包括不限于 工具、方法、学生的现状。谢谢各位助教。

邹欣老师和周筠编辑提供的领跑黄衫,着实让同学们兴奋了一把。来自“官方”的看得见的肯定,仍然是同学们追求的重要目标和强大动力。

很多学生的技术博客,邹欣老师也给也点评或者建议。他的点评和建议从来不是泛泛的,而是切中肯綮。一方面,我感慨邹欣老师同时点评这么多高校和学生,作为教师我也能学到不少,心存感激。另一方面,我和郑蕊私下交流过,我们点评一篇需要半小时以上,而邹老师只需要八九分钟,质量却是比我们更高。所谓高手和菜鸟的差别,他们少犯错,他们效率更高。能让我们亲眼看到高山仰止,也是幸运。

除了邹欣老师以外,还有几位专家也参与了点评。他们是maverick@柳园 (余晟), 李暘,无效的昵称(来自阿里的曾同学)。几位共同指出一个特别重要的问题,代码规范和文档规范。这不仅是学生的问题,也是教师的问题。如果有下一次课程,我会注意改进。谢谢。maverick@柳园就规范问题还给出过具体的建议,文档模板。这一点我心尚存疑,对于学生的主动性培养和适当引导,我仍然在犹豫之间,此时就以邹欣老师提供的教辅助材料为准。谢谢各位。

为了能得到来自校外的专家的点评,我在助教和构建之法微信群中,每一周都发布广告,恳请指导和鼓励。后来我不敢再继续发布消息了,因为同学们做得实在令我汗颜。如同我在课堂上说的,所有的一切都是公开的,代码袒露在所有人的面前,东北师大和你个人的能力如何,是不是会被别人藐视,无论你多么爱国和爱校,事实也就是这样。尊重不是靠恳求和隐瞒得到的,而是靠实力。

在教学中,我还得到了牛宝乐老师的帮助,他向我推荐和提供了幻飞龙博士开发的工具,把EXCEL格式的文件转换成Markdown格式。我用这一工具处理每周发布的成绩,以及成绩计算的依据。非常有效,节省了不少时间。谢谢二位。

两位旁听生,郑蕊和齐嘉亮,成为整个班级和团队的中坚力量,在带动别的同学上面起到了极大的作用,让我放心不少。谢谢。

5. 教学内容

工程。从第2次课程开始,教师持续地强调 这是工程课程,不是编程课程。编程的经验对于 项目的结果 起到了非常关键的作用,这一点从亮哥在耐撕团队的作用、刘伟硕换组以后立即突破OneZero团队的关键技术问题(数据库连接和操作)、高鑫加盟暴打团队以后团队起死回生 可以旁证。但是超越编程经验的工程思想,才是本课程教学的重点。不少同学在学期中或学期末的时候表达了理解 工程控制 的重要性,不过教师并不确认这种表达到底多少真诚,有多少可实施的愿望。

为了强化工程的体会(以及降低技术风险),教师强制要求,不得采用需要探索的技术,只能使用现在已经熟练掌握的技术。直接要求而不讨论,禁止了在统计文本的词频中使用 Hadoop、禁止了使用某种框架。教师也有过担心,万一同学们只会做console程序,连GUI和web前端都做不出,那么产品的效果得多么惨不忍睹。邹欣老师教导我(大意如此)说,那就是愿望和能力间的差距太大,还是能出来啥就做啥 — 做出不来的,光想也是没用,发布才是硬道理。

还是为了强化工程的体会,教师特别若干次强调 边界,并在需求分析、功能列表、SCRUM中再次援引边界。边界是一个系统与外界的分隔也是连接,是允许调用的接口规范,支持的功能的集合,use case driven指定的整个工程的开始端,也是拒绝服务的依据。

估算和度量。对时间(PSP)、工作量(技术博客字数累积、代码行数累积、进度条)的度量要求,对时间的(预计)估算要求。冉华同学的项目在时间和工作量估算上受到教师的直接指导,他的进步(至少体会上)非常明显。工程思想要求所有的效果都是可观测的,所有的猜测(模型)是可验证的。计算机系的同学实验经验还远远不足,“我猜”而不验证仍然经常出现。

以上两点,是不限于软件范围的一般性工程思想,是教学中的重点。教师相信中国软件工程学科教程[https://book.douban.com/subject/1653554/]中的观点(大意),软件工程与一般工程间的区别远比我们通常认为的要小得多,应该首先注意到它是 工程,其次才是软件相关。

结对编程。一定程度上解决了某些同学编程基础薄弱的问题,但是实施不持久。实施了一段以后,同学们以 时间、地点、导师部署的工作量大 等理由开始搪塞。关于同学们对于知识的尊重和对训练的轻视,后面会再谈。由于此时团队项目开始出现团体reciew和团体一起编程的情况,教师对于结对报告没再坚持。

规范,文档排版,用词和造句,变量命名。这些在前期有提及,并且安排了作业,但是在时间驱动团队项目的压力之下,教师和学生都放弃了这对规范的要求。

版本控制。要求使用github。同学们在团队项目开始后,抱怨网络现状和响应速度,纷纷放弃使用github,不过版本控制的习惯保留了下来。

技术博客。要求发表在 cnblogs 上。有同学抱怨但是全都服从了。遵循虽然不见得最优但是并不明显愚蠢的上级要求,也是成为工程师的一课。希望同学们在此能有收获。

版权。我们提到了文字复制粘贴的侵权问题,也讨论到图片引用。从同学们发布的技术博客文字和课堂争论来看,并未就版权的界定(比如引用图片是否算以“学习”为目的,不营利是不是就可以盗版)达成一致意见。在本课程中,教师视引起争论为达到效果,不在教学中作更深入的探讨。

6. 缺憾及体会

1)知识和训练。同学们普遍而长期地忽视训练。

同学们普遍而长期地忽视训练,如果我们认可他们相对地更重视一些知识的话,虽然他们最重视的是感受(“这个老师真和蔼,全心全意地爱学生,这样的才是好老师”)和态度(“我反对我赞同,不转不是中国人”)。决定成败决定效果的,直接地不是感受和态度,而是技术。现在比较普遍地能够接受的,即使在人民战争中,人民的认可如此重要,但是在最终和敌人刺刀相见的时候,意志远不如技术重要。打架是个技术活,工程也是。头缠红带如果只发生在临期末了,改变不了战局。

在课堂中,教师也屡次提到,知识是可以传授的,告诉你你就知道,而技能是不能传授,只能通过训练习得。游泳、骑自行车、弹琴、编程,这些技能只能通过训练获得,你仅仅知道也是白扯。邹欣老师在《构建之法》中有生动的比喻,一个在健身房里参观的学员,是不会自动长出一身肌肉来的,只要你不*主动*运动,亲自克服阻力,无论教练对其他学员的教学方法有多么地好,教练多么地帅和态度友善,你的愿望有多么热切。

例如,在本学期实际的教学中,同学们对于结对编程最初表现出强烈的轻视,觉得明白道理就行了。在工程实践中,也倾向于乐于观摩,而不希望投入时间;在课堂中,倾向于听教师讲单口相声,“啊”地一拍大腿或者频频点头,而不希望做作业。在课余的项目中,我也注意到学生们普遍地具有这种估向,希望真项目、有实际用途的项目、有好的效果的项目,同时希望工作量要少,希望多学知识,而不是实践知识。针对这一点,在课堂中,教师多次提到,资本家不会因为你会什么知识而付你钱,只会因为你做了什么而付钱。

对于训练的否定态度,以前也经常有项目组的同学对我说,“老师,我还得学习呢。”也就是说在同学们的心目中,项目研发,不过是业余的爱好,并不是学习的一部分,读书考试才是真正的学习。下意识中,掌握了知识,或者把某书的电子版搞到手了,就完事大吉。其实这只是开始,甚至远未开始。知识,从写出代码第一行时,在实践中,才真正开始掌握。知乎中有人问,“编译原理和算法导论是不是屠龙技 有技而无龙可屠?”我在回答中说,“除非真正屠龙过,否则不能确定掌握了技术--做习题是不够的。因此“有技(而无龙可屠)”是个伪命题。”道理是一样的。

当然,我能够理解,同学们经常看到世界充满欺骗和吹嘘,甚至我们已经习惯。说一套做一套,理论和实践毫不相关,要求别人的道德准则和自己亲自实践的泾渭分明。不过,如果我们所做的和我们宣称所相信的如此不同,我们得是多么精神分裂啊。所以,试一试,按单一的原则生活,实践你相信的原则。拒绝你不相信的。

知识与实践(及训练)应该是统一的。

2)主动地参与世界。积极性。同学们普遍高冷。

本学期有一个抢跑项目(把 [http://www.cnblogs.com/xinz/p/3852177.html] 的量表做成APP或网上调查问卷,并发布在微信朋友圈中),有三个名额,但应者寥寥,最终只有两位同学参与,并且有一位是教师单独动员的。

这个抢跑项目初看很简单,简单到同学们不屑于抬起手指。这种傲慢在学习工作中也是普遍的,“显然啊”是不少人的口头语,颇有一种“你怎么这么笨就是不明白呢”,即使后来深入了解发现并不简单甚至“显然”自己错了的时候,也气势不减。

简单的项目不做,复杂的项目做不来。在课堂上也常这样,显而易见的问题不吱声,稍微难的问题不敢吱声。所以,沉默的大多数,寂静的春天。假装大人,掩饰自己的不足,故作淡定,不参与不表现,不评论不反对不支持。

第一次第二要求结对,很多同学不做;再三强调推动,终于做了,但是体会不乐意写或不乐意多写。要求互评效果更差,只有一两位同学参与并保持。教师提供了“他山之玉”,转引邹欣老师整理的其他高校的技术博客汇总,似乎没有几位同学看,从在课堂中对作业要求的表现可以猜测。

“主动地参与世界”是世界不放弃的前提。还是在知乎上看到的一个吐槽,某高校几位女同学在大雨天被浇到了,而路上所有独自撑着伞的男同学都静静地看着她们在雨里走。有位回答得与我们刚刚提到的主题正相关,他说,你如果有求于人,要主动提出,否则别人会以为你享受雨中的散步;没有人有闲工夫看你,所以我们根本不知道你在雨里。“主动地参与世界”,不要期待世界来求你。绝大多数同学的技术远没有达到可以隐居的程度,不过作法上已经很有大师的样子了。

3)主动地参与世界。人类语言和代码写作。

课程要求同学们每周发布技术博客,课程还要求期末交课程论文。从技术博客和现已看到的课程论文来看,篇幅都短得可怜。课程论文谈体会,还没有教师的体会一半儿长的同学,不觉得惭愧么,或者教师该为这一学期让你收获如此地少而说声抱歉?

不少同学可能会说,“没有什么好说的。”

抛掉我们课程中提到的,错误的承前省和代词使用,是网络贴子主要的错误来源,认为读者知道你所知道的信息,是一个错误的假设。如果读者已经知道你所知道的一切,那么心有灵犀的情况下,沟通就毫无必要—也许你确实认为报告、技术博客、论文,只是形式化的仪式而已。向别人解释自己的动机、技术路线,在毕业论文和项目答辩中阐述你所认为的重点难点,不仅是使得别人了解你,也是评定专家确认你了解你所说的内容的重要手段。对于从北京到走向世界的途径如果你说,“靠脚”或者“没有必要,最好的我们都已经有了”,那么别人至少了解你的方法论或者价值观,而你说“那不显然么”,除了傲慢的态度,别人对你没有任何新增的了解。

有个心理学或教育学故事告诉我们,不了解别人不是自私,而是幼稚。故事说,令孩子A观察孩子B的行为,并回答问题。有个人对被观察者孩子B展示糖果并放在抽屉里,然后在孩子B短暂离开时把糖果从抽屉里拿出来放到口袋里。问孩子A,孩子B回来以后会到哪里找糖果。有一些孩子A回答,孩子B会在口袋里找糖果。这些孩子A并不知道,孩子B不知道糖果转移这一信息。

代码、文档、报告、技术博客,都是告之另一些人,他们所不知道的信息。主动地参与世界,在代码和人类语言写作中充分预估别人可能不知道,展示自己的友善,而不是展示自己的聪明。

如果你不知道应该如何表达,或者表达哪些信息,那么 多读书,多读别人的经验之谈,多读代码,多看看别人是怎么写的。不要沉浸在自己的小世界里,你不注意别人,就不知道别人需要什么信息,期待阅读什么。多想到别人期待什么,而不是你意图展示什么。这样,能避免写作和代码词不达意。你的个性和态度,没有人乐于为此付钱。帮助别人,别人才会付钱给你;请我们欣赏你的个性和态度,你需要付钱给我们。

4)时间。快节奏,短迭代。时间驱动。对时间的估算和度量。

课程每周一次。也就是说,如果师生在此中间没有任何沟通,那么学生在此时所犯的错误,可能要7天之后才能得以纠正;学生是否理解纠正,需要再一个7天老师才能观察到效果。如此往复,我们在一个学期16周中也不能交流多少东西。所以,提高工作节奏,以尽可能短的迭代来完成任务非常必要。这也是Agile/Xp方法论的核心之一,也是RUP接受的理念。

齐嘉亮、刘伟硕、濮成林和夏一鸣都采用过短迭代完成作业。在作业部置的第二天,就已经提交一个版本,教师(和邹欣老师)给出的修改意见、增补的工作要求,在接下来本周过完以前再提交一次,可能根据修改意见再提交一次。这样,别人一次作业,他们不仅多了两三次的工作量(也即收获),而且远超这些,因为后面的几次作业是在教师针对性的指导之下的。

相比之下,有些同学采取了等、靠、拖的策略。在作业截止时间最后几分钟提交,其中一个借口是“我希望尽可能完美”――但是不会比教师直接指导下的修改更完美,并且展示完美不是我们学习的目的。教师给出修改意见以后,不少同学说“我会在下次/以后的作业中改正”,这基本等价于“老师,我已经给你留了面子,表达了充分的尊重,请不要逼我太甚”或者“我以后会改的,请不要再烦了我好咩”。如果那是错误,为什么不在本次改正?如果这是你期待的希望的“真正的”项目,不改正的错误会导致你白做,甚至可能赔偿损失。这种态度让我想起郭大侠的女儿郭芙,她砍了杨过的右臂,然后哭闹说,“我的确砍了你的胳膊,可是我被爹爹骂也骂了,对你道歉也道了,你还想怎么样啊。”郭芙之娇横可能连你也不能接受,不过那毕竟不是她本人的胳膊,而这是你本人的问题。

也有的同学会说,我改你指出的毛病已经够费劲了,"你还想怎么样啊"。笑话又说,期末的突击学习的难度,取决于你是复习还是预习。学生费劲、教师频繁地提出修改要求,改了一个毛病又整出一个来,一方面是因为不改完第一个,第二个毛病无从改起;另一方面,实在是因为某些同学的基础太差啊。好吧,那不全是你的责任,而是以前你的学校、学院、教师的责任,让我们一起抱怨吧。然后静等这个世界变得更美好…和宽容。

关于时间,邹欣老师还提到发布要求 时间驱动。没有截止时间的压力,同学们不定哪天才能完成—一般是最后一天开始动手。夏一鸣同学在期末总结时感叹,学期初的愿望有两个,其一是 题目难道能循序渐进,其二是 如果太难,希望能放宽时限。一个也没有实现,不过他大大地成熟了,已经进步到不再有这两个愿望,而是“老师是不是可以分配给我下一个任务了。”

时间要求是个硬线,在教学中,宁可缩小功能范围、降低质量,也不能超时。就在要求的那个时间,无论如何,程序要发布要可执行。我喜欢说的一句不太动听的话,在规定的时间规定的任务必须交付,如果做得像屎一样,就交付屎一样的工作,并接受别人对我们屎一样的评价。下次更努力一些,不要在这一次就求饶。

与时间相关的最后一个问题,同学们普遍缺乏对时间的估算和度量的意识,如果说对代码量的估算和度量还有那么一点意识的话。时间是工程中最重要的资源(没有之一,因为时间直接地就是生命,别的都不是),所以对于自己做类似项目的能力的度量应该持续进行,这也应该成为事后review诸葛亮会议的重要内容,并根据这种度量一次次在新项目开始前估算时间,在项目结束后对比事前估算与事后度量,增强下次的估算能力。自动控制中常用的PID方法、机器学习中各种基于经验的方法、读者故事里鲨鱼怕疼不敢撞玻璃那样的浪漫的基本原理也大抵如此。我们怎么能在工程中有时重视估算和度量,而对最重要的时间却如此忽略。多么精分啊。

5)规范

规范不止是代码规范,还有作业要求,用人类语言表述的作业要求的条目。

为什么没有一再地强调规范,因为同学们普遍地达不到更低的要求,所以教师放弃了规范这样更高的要求。时间、工作量、工作报告质量、视频,很多不能达到最低要求,有不少同学直接忽略部分作业条目,当没看见。同学们根据工作量和时间调整要求,而不是根据要求调整投入的工作量和工作时间。

还是在知乎编译原理是否屠龙技一问中,我这样回答,“能找到的活儿太差的时候,觉察不到技术的必要。成天跟小孩打架,不用练力量敏捷抗打击;成天盖狗窝,不需要图纸和水泥标号。如果理想就是这样,龙只是传说,屠龙技当然毫无用处。”如果你满足于这样的生活,不希望精益求精成为一个更优秀的工程师,我又有什么法子。我当然知道优秀的教师能够“有教无类”,“没有差生,只有差教师”,可是,偏偏我不是优秀的教师,咱们可怎么办呢。

对于不完成作业的全部这一点,教师考虑过以更详细和严厉的规则来应对:作业应该针对小项倒扣分,而不是全部作业都不完成才倒扣分。不过,教师担心这会开启 狱警-囚徒模式,尤其学生是研究生阶段的 成年人,理应获得这样程度的尊重。

说起尊重,我想起一个故事。据说侵略者为了瓦解印弟安人,对战士说,“你在部落里有什么样的权力?”战士回答,“我有冲锋在前的权力。”冲锋在前,是一种权力,这是尊重的来源。我尊重你是成年人,作法就是像对待成年人一定对待你,绝不称你为“孩子”“那个孩子”“那些孩子”,绝不轻拍你的高贵的头以示亲昵;我尊重女性,作法就是像对待男性一样对待女性,尊重她们冲锋在前的权力,所有的爱护都无声地宣布“你是弱者,自觉承认”。

我尊重你,尊重你按约定完成任务的自觉和按规范完成的能力。你按约定和规范完成任务,是对我的尊重的尊重,也是对你自己冲锋在前的权力的尊重。你之所以能看到的我的愤怒和失望,是因为你放弃了权利,你没有侮辱了你自己也侮辱了我,也是因为我对自己的无能的认可和恐惧。

6)学生观摩。现实,外界的限制。

邹欣老师希望学生能够观摩final发布和各次发布,他希望退课的同学能回来看看,看看失去了什么;他希望本科生也能来看看,看看可能在将来学到什么。邹欣老师还希望成绩能够严格执行平时作业的标准,并且平时作业应该占到应该的比重。

这些期待,我很惭愧,没能全部实现。作为主讲教师,我切身体会其中的难处,有些超过了时间花费、知识结构和技能,进入了我们所隶属的单位的组织结构(和课程体系)。课程教学只是上级(我不是在讨论赞同或反对高校行政化)要求的诸多工作的一部分,还有很多别的工作,这并不是最主要的原因。更重要的原因是,如果那么做,所付出的代价。不是克服困难所付出的努力,而是克服困难所需要承担的后果。所以,所谓“尽我所能”“不惜一切代价”我从来也没有脸去说,也不能以此要求我的同学们。

prison

7. 总结

回望来时的路。构建之法 东北师大站 2016春季学期,终于结束了。

第4周的时候,我曾经写过鸡汤如下,赞扬2位领跑同学和当时尚未放弃的18位同学。其实情形一直这样艰难,从来也没有改变。

他们的成绩反映的是这样的场景下的胜利:
你是一位将军,
部队弹尽粮绝,而且很饿;
战士战术技能很差,装备落后;
行军在敌国的沼泽里,风声鹤唳;
敌人有空中支援,有坦克,有热的饭菜和热水;
上级是没脑的杨贵福,战略垃圾,脾气暴躁,
他决定此刻立即开始,进攻前方的碉堡,既没有迫击炮也没有照明弹,
只有炸-药-包。

你的下级准备解散部队,准备撤出战场,准备起义反对你。
你说,不惜一切代价,16周突袭。
这就是4周以来的战况,我们还活着。

我们还有12周战斗。

继续冲锋。

此刻,继续冲锋。
如果你为感想和收获还不到教师的一半长度而惭愧,此刻,继续冲锋,不要等到下一次作业再改进。没有下一次。

bitter

————————————————————

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]

Debug一例,Wordpress 插件 Blogger Importer Extended 导入 blogger 图片问题

1. 背景和问题

2月25日至29日,约12小时,中间有预计会有长时间导入的过程,享受咖啡和小说。

起初,高博先生微信我,向我提供博客空间。他鼓励我,这样爱写作的人,应该坚持下去。我申请了域名,高博先生提供空间并架设wordpress已毕。既然准备长时间驻守,我就打算把以前在 blogger、CSDN、短乎 上的博客全导过来,计1478篇。

问题就是从导入 blogger 开始的。我和高博先生都发现,有些贴子的图片不见了。

最先确认的是,一部分不见的图片,是因为我从知乎贴过来,如果我作为知道用户登录了知乎,那么我是可以在导入后的文章中看到图片的;而高博先生及其他人就看不到。我以前从知乎向CSDN转贴的时候,还想过,知乎真是大方有礼的网站啊,居然可以直接盗链。恩,似乎也不是。如果盗链的时候就告知还好,竟然不声不响么……这部分图片我手动一张张重新上传过,OK了。

但是仍然有几张图片显示不出来。在网上搜索了一下,有人提到 (大意) ,"图片都下载到wordpress服务器了,在文件系统中找到了,但是在博文中不显示"。似乎正是这样啊。

跟着讨论走下去,发现导入插件的作者9个月前说打算解决,然后就没了消息。下面一大堆回贴,"我也是这个毛病啊"。

高博先生说,用正则表达式容易定位出哪些图片有问题,不过如果找到bug,方便大家就更好了。他提到用正则表达式的时候,我心说惭愧,竟然没有第一时间想到;当他说方便大家的时候,我觉得"压出皮袍里的小来了"。

见贤思齐,跟踪一下这个bug在哪里吧。于是动手,12个小时,及这篇贴子。

我用的wordpress插件,实现 blogger -> wordpress 的,是这个:

Blogger Importer Extended Migrates your Blogger blog to WordPress.  Version 1.3 | By Yuri Farina

2. 故障重现,实验床: 受控,孤立

得先找到bug,然后才能改bug,而找bug,又需要先重现bug的现象。这是个简单而直接的道理,不过不少同学似乎不怎么相信和实践呢。我经常听到这样的问题,"老师你说我看啥书才能编程好呢",这类似于"你说我吃点啥能减肥"。

万军丛中定位将军,是件困难的事,杀了他,通常不过是一刀的事。
灯光下的豹
故障重现,要求能一次又一次,在相同的条件下,触发相同的现象。而这个现象,就是你希望它消失的那个。要给药退烧,必先测体温。你猜大约是发烧了吧,猜大约是肺部感染,猜大约哈希表比数组来得快,都是猜,所有的猜测,无论是否有理论支持,在实验数据面前都是猜瞎。不少同学上来就改改这看看吧,改改那看看吧。然后某次现象消失了,他就误认为问题解决了。这叫做work around (绕过问题),不是解决。

故障重现有时需要1.特别长的时间,或者2.特别宝贵的资源,或者3.生产环境不允许动作,或者4.代码特别长特别复杂,这时需要 实验床。实验床有利于在*受控*的环境下触发特定的条件,从而导致特定的现象,方便重复。实验床有利于孤立问题使之与其他复杂的环境和因素解耦。

如果能证实实验床与生产环境是一致的,那么bug的触发条件、现象也会是一致的。实验床就成为生产环境的一个模型。在模型中思考和操作,是重要的科学、技术和工程手段。

这次找bug架设实验床,我注意了以下两点。

2.1 先本地测试,再更新到远程,xampp

重现故障现象,而且不知道是哪些图片 (更重要的是在何种条件下) 有问题,最朴素的做法是从 blogger 到 wordpress 同步实验,一次又一次。每次实验改变单一的因素,看看故障是否再现/消失。

从 blogger 到 高博先生提供的wordpress,速度也没有多快,而且我担心他的流量和带宽占用。

所以实验床应该架设在本地。

我在我自己的PC机上架设了一个 xampp,装上 wordpress,从 blogger 到我本地的 wordpress 同步。这样,我至少不用担心高博先生在哪个时区,是否方便打扰,何时可以响应我的请求重启服务器、清空数据库、重置 wordpress。等我本地找到bug修改完,再在远程的服务器上修改。

我不止一次对编程的伙伴们说,把手册下载安装到本地,但是网断的时候他们还是会说,"网断了查不出手册啊,编不了程序了啊。"我想说,没有人可以依靠,除了你自己;成为可以被别人依靠的人。

2.2 小规模实验,确保触发故障现象快速精确

同步所有的博客文章,才能触发问题。但是执行一次同步,需要耗费两三个小时。有些动作,并不需要触发问题,所以同步的不必是博客文章中的全部。这些动作包括不限于,1.下面会提到的加入日志记录语句 (并测试是否生效),2.猜测某个因素是造成问题的原因,修改这个因素以后测试效果。

所以实验床应该短小精悍。

我注册了一个新的 blogger 站点,发一两个贴子,专用于 wordpress 拉取。这样能确保触发故障现象的因素 快速 而 精确。想调校哪个参数立即就可以测试,不必等到一千多篇博文同步的两三个小时。而且更容易确保造成现象的原因就是某个因素,而不是整个庞大项目中的某个你无意中设置的变量。

我就在这个新的 blogger 站点上发贴子,粘图片,每次同步几秒钟。

架设实验床的时间,考虑实验床如何架设的时间,这些都是值得的,甚至单轮测试所花费的时间缩短的效益就值回来了。

3. 故障定位,日志: 受控,易于追溯

有了实验床,就可以罗列可能造成问题的因素A,B,C,D ,然后设计实验,一一验证或证否。所以,故障定位,是这样的技术手段,在受控 (各种因素)条件下,重复过程,以检验假设。

3.1 跟踪手段选择,error_log,可长期留存的 vs. 瞬间消失的
清湖
重现故障,初学者希望立即、马上、直接看到效果,铛地一声弹出个对话框,告诉他出错了。

人类不同于动物的一个重要特征,是可以理性地推迟期待的效果。然后成批次处理。日志输出输出输出输出,然后分析分析分析分析,而不是 输出分析输出分析输出分析。在操作系统进程调度算法中,效率最高的,是成批处理,不分时,不中断,不切换进程。学习和工作效率最高的做法,是集中注意力,完成一件工件,然后再开启新的任务。

日志输出、TDD、自动化测试、脚本,甚至程序本身,都遵循了这样的原则。

用日志跟踪,而不是实时显示,能避免不少问题。比如,工程师借口说,"当时我操作啥我也不记得了,反正故障消失了,等以后再出现再说吧。"你可以一次又一次分析日志,条件、现象都在日志中记录中,而不必非得再开启一次实验才能回想起来。"我输入什么这个现象才出现来着,唉呀状态不好,忘了。"工程方法让每一个人都不必非得是天才,也能做好工作。

我选择 php 本身内置的 error_log,日志写到error.log中,而不是另打开一个文件写进去。如无必要,勿增实体。紧着现成的用。

3.2 读代码框架,了解流程,确保日志可以被触发

接下来我大致读了 wordpress (之前粗读过一本书和 wordpress 手册)代码,然后沿着这样的顺序找到准备设置日志记录的代码行:

wordpress -> blogger-importer-extended插件-> importer.php -> 函数-> 代码行

设置位置的原则,跟猎人设置陷阱的原则是一样的,1.要确保目标猎物会经过此处,2.目标猎物会触发陷阱,3.当触发时能够把猎物抓住。

就这个案例而言,对应的是,1.跑每次实验流程的时候,希望执行 发现图片、下载图片、改博文中图片的地址 这些操作的时候,能够记录这些动作,成功的和失败的。2.失败的图片,那些图片下载了,但是博文中的地址指向却没有变更的,一定要记录下来。不希望跑了一次实验,有失败的现象出现,但是却没有捕捉到。3.当触发了日志记录动作以后,希望把准备用于分析的信息都记录下来。不希望跑了一次实验,现象也发生了,也记录下来现象发生了,但是发生的现象以及此刻变量的现象没有记录。

3.3 输出的字段,0.易于找到,1.触发条件,2.assert

记录哪些字段呢?我想的包括: 0.易于找到,1.触发条件,2.期待的,实际的

第一,易于找到,要容易在很多行日志里找到,所以加上明显的分隔线和换行。

在Linux下,我就开个终端,tail -f error.log,完成一次实验,往上翻到刚刚开始实验时候,往下读。这次是windwos,我记一下实验开始的时间,然后在日志里找,或者在每次实验时在日志里写个明显标记,从结尾往上,最后一个标记就是本次实验的开始。

第二,要记录触发的条件
直路
分析的时候,找到出故障的那条,看何种条件下会触发。这就是程序设计语言里的" if ( condition ) "里的condition。如果每当这个条件都会导致故障,就可以怀疑这个条件可能就是原因。

需要注意的是,因为找到bug以前还不知道触发的条件,所以尽可能多记一些怀疑的条件 (在眼花缭乱以前),每次实验就能多分析一些因素。

我按下面这样日志。

error_log("-foreach post----\n"
.  print_r($post->post_date,true)."\n"
.  print_r($post->post_title,true) . "\n"
.  print_r($found_images, true), 0);

这一条记录了触发日志记录 (不是触发故障,那需要根据日志人工判断)的条件foreach post,遍历每篇博文的时候;记录了博文的日期 post_date,博文的标题 post_title,图片的某个信息 (路径?名字?很多图片的名字拼接在一起?)。

第三,你期待会是某个值的变量,如果它值得怀疑,记录它。对比你期待的值和实践发生的值,如果有差异,那就是问题的原因。这个变量,既可能是条件中的,也可能是参与计算和输出的。

在这里 $found_images 就是值得怀疑的,我打印了不少次这个变量,在不同的位置。C++开发原则之一,assert你认为本该如此的那些量。这时我做的差不多根据同一原理。

3.4 日志分析,触发事件的特征

接下来就是人力工程了,一行行读代码,找到故障发生 (我们记录了进入那样的分支,比如那些成功的操作以外的else)的地方,看触发故障时 各个因素 (条件)都是什么样的。

故障发生的条件,是不是有规律?每当这个时候我就想起包师弟,归纳能力超强,能从乱七八糟毫无规律的现象中发现模式。恩,他的模式匹配算法可能比较好,很多智商测试题都是考察归纳能力的。

这次,我独立找到了模式。中文。

如果文件名是中文,比如"鹦鹉螺",那么就会发生故障。一共15张图片符合条件。

进而发现,所有文件名是中文的,都发生了故障;所有文件名是英文的,都没有故障;所有没有故障的,都是英文文件名;所有发生故障的,都是文件名中文。

4. 解决

豹
万军丛中取上将首级。万军丛中找到上将很花时间,此次约10小时。斩杀上将,只是一刀,约几秒钟。验证上将确实死透了,需要的时间稍微长一些,先实验床,然后生产环境。

一共只改了一行,如下,正是中文文件名容易出现的问题。原来的代码,在文件系统中和在博文的 img src 中,分别 urlencode 和 没有urlencode,所以当查找那个文件时,按期待的名字,它不存在。

下面的代码,注释了的那行,就是bug所在,注释那行的下面,是我修改的结果。

wordpress\wp-content\blogger-importer-extended\includes\importer.php:
if(!is_wp_error($image)) {
$attachment = wp_get_attachment_image_src($image, 'large');
//$content = str_replace($found_image, $attachment[0], $content);
$content = str_replace($found_image, dirname($attachment[0]).'/'.urlencode(basename($attachment[0])), $content);

5. 修改工具,还是修改产品;一般性的程度

我没有修修改插件的代码,仅仅测试通过。我手动修改了在高博先生那的wordpress里的15篇博文。我选择的是修改产品,而不是工具。

鉴于出现这个问题的,可能主要都是能读懂中文的,所以我写了这篇博文,而不是修改插件再发布。

修改工具能更一般性地解决问题,更大范围地产生效益。我惭愧,还是没有高博先生那么有高度和乐于助人。

5. 感谢

感谢高博先生的空间和时间。

感谢winguse先生提供链路,使我得以访问 blogger。blogger,就是 google 的 blogspot,如果不能访问到的话,我没法授权 google 允许导出,也不能导到我的本地测试PC机中。

在跟高博先生和winguse先生讨论的时候,我都很享受,高效率地交流使用条款和技术路线。三言两语可决,毫不罗嗦。

感谢叶卡编辑让我认识高博先生,及那么多精彩的人。

感谢 Yuri Farina 开发 Blogger Importer Extended 插件,使我得以取回自2007年2月以来的历史博文。
电线杆
------------------------------------------------------------

博客会手工同步到以下地址:

[http://zhuanlan.zhihu.com/younggift]

[https://younggift.net/]

[http://blog.csdn.net/younggift]

[http://giftdotyoung.blogspot.com]