posts - 11, comments - 9, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2012年6月16日

原来Markdown如此之方便,github又提供了page服务,还能用上git,真是无法无天了!

http://www.100hack.com

或者
http://cuixin.github.com

posted @ 2013-06-29 01:30 steven.cui 阅读(217) | 评论 (0)编辑 收藏

第5章 调试你的大脑


我从来都不想成为怪人,但别人都认为我想。

——弗兰克.扎帕,美国作曲家、音乐家、电影导演


直觉是伟大的, 除了当它不伟大的时候。

我们必须直视自己,“调试”(debug)自己的大脑。

关于debugging,可以自己扩展阅读,软件是有人创造的,错误难免。

为什么这么说呢?人类大脑又不是开源软件,没法找到代码去修正,只是展示出错的地方,但你却能知道自己的缺陷在哪里,只能尽量避免,却几乎难以修正。这就是人,而不是计算机:

     1.认知偏见:思维如何被误导

     2.时代影响:同代人如何影响你

     3.个性倾向:个性如何影响思维

     4.硬件故障:大脑较老区域如何压制较聪明的区域


了解认知偏见

     Wikipedia列举了大约90多种认知偏见,书中着重举了几个值得重视的偏见:

   思维定势

     思维定势(Thinking Set) 是由先前的活动而造成的一种对活动的特殊的心理准备状态,或活动的倾向性。在环境不变的条件下,定势使人能够应用已掌握的方法迅速解决问题。而在情境发生变化时,它则会妨碍人采用新的方法。消极的思维定势是束缚创造性思维的枷锁。

   基本归因错误

     归因理论的一个现象,即人们常常把他人的行为归因于人格或态度等内在特质上,而忽略他们所处情境的重要性。比如,尽管我们在评价他人的行为时有充分的证据支持,但我们总是倾向于低估外部因素的影响,而高估内部或个人因素的影响。这种现象解释了当销售人员的业绩不佳时,销售经理更倾向于将其归因于下属的懒惰而不是竞争对手的实力。

  基本归因错误(fundamental attribution error,FAE)描绘人们在考察某些行为或后果的原因时高估倾向性因素(谴责或赞誉人)、低估情境性因素(谴责或赞誉环境)的双重倾向。

   自私的偏见

     这种偏见使人们相信,项目的成功是我的功劳,失败则与我无关。这种行为可能是一种个人防御机制导致的,但是请记住你也是系统的一部分——无论结果好与坏。

    需要定论

     我们对疑问和不确定性感到不舒服,我们会竭尽全力解决不确定性。其实不确定性有时候是件好事,选择是开放的。如果强行把不确定的事情强行的定论,会迫使你选择放弃,易于犯错,例如你宣布了一项项目截止日期,并没有能力移除内在的不确定性,它只是一种自我掩饰。说到这里,我们常说靠谱还是不靠谱,我个人是比较烦不靠谱的人,而我爱人却总结出,不靠谱的人有时候往往做朋友比靠谱的人好相处,而且有时候能帮到你。

     因为不靠谱的人在事情模棱两可的时候就可以承诺,但你别太把承诺当回事,也许他看似不靠谱的事情,真的就能办到。因为靠谱的人从来不做没把握的事情,不敢于尝试,不去争取尝试甚至,特别觉得一旦说出去的话就得全部做到,要不就只字未提,听她说完,身边的朋友的确,虽然有些看似不靠谱的,却真心对待的朋友,他们不是不靠谱,而是敢于给你帮助。


    认可上的偏见

     每个人都根据自己的成见和喜好原则来选择相应的事实。

    曝光效应

     会因为习惯和熟悉某种事物对其偏爱,这包括不在好用或者出错的工具或者技术。

     霍桑效应/宣泄效应

     1)社会心理学家所说的“霍桑效应”也就是所谓“宣泄效应”。霍桑工厂是美国西部电器公司的一家分厂。为了提高工作效率,这个厂请来包括心理学家在内的各种专家,在约两年的时间内找工人谈话两万余人次,耐心听取工人对管理的意见和抱怨,让他们尽情地宣泄出来。结果,霍桑厂的工作效率大大提高。这种奇妙的现象就被称作“霍桑效应”。

     2)1924年11月,以哈佛大学心理专家梅奥为首的研究小组进驻西屋(威斯汀豪斯)电气公司的霍桑工厂,他们的初衷是试图通过改善工作条件与环境等外在因素,找到提高劳动生产率的途径。他们选定了继电器车间的六名女工作为观察对象。在七个阶段的试验中,支持人不断改变照明、工资、休息时间、午餐、环境等因素,希望能发现这些因素和生产率的关系——这是传统管理理论所坚持的观点。但是很遗憾,不管外在因素怎么改变,试验组的生产来效率一直未上升。

     历时九年的实验和研究,学者们终于意识到了人不仅仅受到外在因素的刺激,更有自身主观上的激励,从而诞生了管理行为理论。就霍桑试验本身来看,当这六个女工被抽出来成为一组的时候,她们就意识到了自己是特殊的群体,是试验的对象,是这些专家一直关心的对象,这种受注意的感觉使得她们加倍努力工作,以证明自己是优秀的,是值得关注的。

     有一所国外的学校,在入学的时候会对每个学生进行智力测试,以智力测验的结果将学生分为优秀班和普通班。结果有一次在例行检查时发现,一年之前入学的一批学生的测验结果由于某种失误被颠倒了,也就是说现在的优秀班其实是普通的孩子,而真正聪明的孩子却在普通班。但是这一年的课程成绩却如同往年一样,优秀班明显高于普通班,并未出现异常。原本普通的孩子被当作优等生关注,他们自己也就认为自己是优秀的,额外的关注加上心理暗示使得丑小鸭真的成了白天鹅。

     实验结论

  1. 改变工作条件和劳动效率之间没有直接的因果关系;
  2. 提高生产效率的决定因素是员工情绪,而不是工作条件;
  3. 关心员工的情感和员工的不满情绪,有助于提高劳动生产率。

研究者认为,这种自然形成的非正式组织(群体),它的职能,对内在于控制其成员的行为,对外则为了保护其成员,使之不受来自管理阶层的干预。这种非正式的组织一般都存在着自然形成的领袖人物。至于它形成的原因,并不完全取决于经济的发展,主要是与更大的社会组织相联系。

霍桑实验最初的研究是探讨一系列控制条件(薪水、车间照明度、湿度、休息间隔,等)对员工工作表现的影响。研究中意外发现,各种试验处理对生产效率都有促进作用,甚至当控制条件回归初始状态时,促进作用仍然存在。这一现象发生在每一名受试验者身上,对于受试验者整体而言,促进作用的结论亦为真。

很显然,实验假设的各项条件并非是唯一的或决定性的生产效率影响因素。对此,乔治·埃尔顿·梅奥George Elton Mayo)以及他的助手们所做的解释是,受试者对于新的实验处理会产生正向反应,即由于环境改变(试验者的出现)而改变行为。所以绩效的提高,并非由实验操控造成。这种效果就是我们所称的“霍桑效应”或“霍索恩效应”(Hawthorne Effect)。

     霍桑效应的优点

  • 能够清楚地发现员工关心的事项。
  • 如果模型建设适当、准确的话,它所给出的解决生产力的办法具有长期的、可持续的特点。
  • 对员工工作条件进行持续性衡量评估,有助于管理者指定长期的战略决策。

     霍桑效应的缺点

  • 一些内在的工作环境属性难以辨识,如组织动力。
  • 生产力模型的参数选择a、b、c比较主观,取决于管理人员的个人认识。
  • 关键性的工作环境属性是动态的,模型需要不断调整反映现实情况。
  • 从总体上来看,生产力模型的准确度与管理人员的个人判断力、敏锐性紧密相关。

     霍桑效应的启示

     “霍桑效应”,也就是社会心理学所说的“宣泄效应”,它给我们的启示是:人在生产或者生活的过程中,对自己未能实现和不能满足的情绪,要把它发泄出来,情绪的发泄对人的身心健康和工作效率都非常有利。

    虚假记忆(让我想到一部片子《罗生门》)

     虚假记忆(pseudo memory)是大脑记忆的信息之间自动的组合导致不真实的回忆。每个人的大脑都可能产生虚假的记忆,或将事物的真实情况扭曲。人们会对自己的记忆坚信不疑,甚至会对大脑编造的谎言信以为真。这并非一种发病过程。所有人都会产生虚假记忆”,特别是关于童年时期亲身经历的场景的记忆。

     符号约简谬论和名词谬论

     移位给事物贴上个标签就意味着理解或者能解释它,例如:当你尝试画一只人手时,L型思维的人会把光线、阴影、纹理的负责性简化为“五条线加一个棍”。就如同人们一直认为天鹅只能是白的。

在这里本人强烈推荐《怪诞心理学》,《影响力》,《引爆点》,《乌合之众》等等,关于心理方面的书籍,每个人都应该读点心理学,不是在于说自己脑子有问题,每个人都是有心理偏差的,正因为心理偏差造成的个体不同,才有各种不同的性格,社会进步的重要标志是能包容各种形式的不同形态存在。

心理偏差是你的个性也好性格也罢,敢于去了解别人和自己本身就是一种对自己思维的挑战,或许说你再向自己发出改变的挑战,也许习惯是最难改变的,我们看似对新鲜事物充满好奇,但如果熟悉一种事物,却很难接受和改变自己替换原有思维。

如果说中国古代皇帝最有作为的——李世民,如果只是但从人心理角度出发分析,对与其“元认知”的能力让其能把国建建设的如此强大——自我批判和自我重塑,而这份能力恰恰是管理者最需要的能力。

预言的失败

     做预言太困难了,特别是关于未来的预测。

                                                ——瑜伽.贝拉,伟大的智者、哲学家兼棒球手

     符号约简(请注意:不是符号简约,这两个字前后颠倒,却意思相差万里)是个非常有害的问题,看个例子,你在尝试画一只人手时,L型把光线、阴影、纹理的复杂性简化为“五条线加一个棍”。这种简化被认为把复杂的现实看做由基本原素的组成:柏拉图立体。

     我们善于将复杂的东西进行简化和抽象,并且计算机编程也是如此之思想,但会让我们陷入误区。

     以前从来没有人认为有黑天鹅的存在,以至于科学界认为没有黑天鹅,知道有一只黑天鹅真的出现了。没发现不等于不存在,很少也不代表没有。

     作为一个团队,我们往往会错过重要的发展,因为我们关注了错误的事情或者提了错误的问题。

     现在,还有人在讨论学习java好还是.net好?N年前的各种争吵:RMI还是CORBA能取得中间件的胜利?Windows还是Linux能赢得桌面的胜利?

     就像是WEB的发展让这些问题毫无意义,Web是典型的黑天鹅,其出乎意料的改变了游戏规则。


“很少“不意味着”没有“

     2012,7.21北京据说60年一遇的暴雨,几乎每年都喊。程序员在写程序的时候,不可能出现这样的bug啊,其实应该说概率低,但不代表没有这种情况发生,花时间查一下认为的不可能的事情吧。不要说:”绝不可能“!


推迟下结论

     软件的制作过程在我本人看来就是一个消除不确定性的过程,而且跟时间成正比,如下图所示:

     到项目末尾时你会达到智力巅峰,而在项目开始时则是最无知的。

     顶住压力。你会做出决策,事情会解决,只不过不是今天。

     适应不确定性,适应敏捷开发,尽可能的用更灵活的技术适应不确定性,适应了不确定性也就等于提高了效率。


难以回忆

     记忆是靠不住的,旧的记忆会随着时间改变,这反而会是你以为某些误解和偏见是对的,不要仅仅依赖你的记忆。中国有句谚语说得好:好记性不如烂笔头。


认清时代的影响

     在这章里作者给出了美国从1901到现在经历的几个时代,从技术和人的思维的变化,相似年龄段的人对某种事物的开发更接近,也就是不同年龄层次的人有代沟。本人不再赘述作者讲述的美国各年代的历史,其实这是我们都难以去逾越的,要想避免你所处时代的特有偏见,最好的方法就是保持多样性。承认一种事物的存在,但却能淡定的确很难。


了解个性倾向

     他人即地狱。

          ——让.保罗.萨特,法国思想家、作家、存在主义哲学

     尊重不同人的不同性格,当你跟别人争辩时,请想一想这点。

     MBTI(Myers Briggs Type Indicator)性格评估测试,在国内有些机构可以做些专业评测,如果想找免费的,可以借助谷歌去找,但如果英文一般的同学想做这个测试,我建议你去百合网,虽然是个婚恋网站,但这个MBTI还是比较专业哦,不过MBTI的测试结果就如同你自己的性格一样,性格有些人会发生改变,但有些人可能一辈子难以改变,曾经我做过测试,经历过几年后的测试有个界限发生了改变,所以不要让MBTI成为你潜意识的引导,而是作为了解自己的途径,但不要太过于相信,而是时常打破自己的”符号约简“。


找出硬件问题

     大脑常犯一些低级错误——硬件问题。

     我曾见看过各种报到,为了一个误会能让人失去理智。。。

     蜥蜴逻辑:

          战斗、逃跑或者恐惧

          立刻行动,不加思考

          领头意识,随意指使你的队友

          守卫领土,不分享信息和秘诀

          受到伤害,愤愤不平,让所有人都知道这是不公平的

          像我这样==好,不像我这样==不好

     你或许认识到以上几点我们都有过呢?

     见样学样,近朱者赤,近墨者黑,情绪就像传染病,常跟一些乐观的人在一起你也就变得乐观了。

     进化行为:当你开始重播这些喜欢的电影时,努力阻止自己,记住:这只是一部电影。

     心灵是自己的地方,在那里可以把地狱变成天堂,也可以把天堂变成地狱。

                                                                                               ——约翰.米尔顿《失乐园》


现在我不知道该思考什么

     在上几章提过,直觉是一种强大的工具,是专家的标志。但直觉可能完全错误,我们认为“正常的”未必是正常的。除了各种偏见,你可能被你自己误导,认为一切都好。

     之前提到关于创造一个R型到L型的转化,也就是说,思考时是全局性和经验性的,然后转换成更常规的实践和技能,从而实现学习过程。

     相信直觉,但是要验证。


最后,测试你自己

     当你坚信某种事情时,问问自己原因。

     尝试问问自己以下问题:

          你怎么知道的?

          谁说的?

          有什么特别的?

          我的做法会如何影响你?

          与什么或者谁比较?

          这总是发生么?你能想到一个特例么?

          如果你这样做了(或者不这样做)会怎么样?

          什么阻止了你?

     实践:

     当发生冲突时,考虑基本性格类型、不同年代的价值观、你的偏见、别人的偏见和情境。通过司考更多因素,是不是更容易解决冲突?

     仔细检查你的立场。你是如何知道你所知道的?什么使你这样认为?


     我们通过逻辑来证明,通过直觉去发现。

                                             ——庞加莱

 

posted @ 2012-08-13 01:38 steven.cui 阅读(355) | 评论 (0)编辑 收藏

原文请参考,如有问题和歧义请指正,谢谢:)

http://clojure.org/vars

变量和全局环境

Clojure是个很实用的语言,偶尔需要将维护和改变数据的值。她提供了4种不同的方式来操作变量:Vars, Refs, Agents, 和Atoms。Vars机制是是指向一个可改变的数据的位置,你可以为每个线程动态的绑定(制定一个新的存储位置)一个新值。Vars可以初始化根绑定(不是必须的),绑定的值对于所有线程都是共享的,但却别的线程就不能重新绑定。因此,要么Var可以为每个线程绑定值,要么使用根绑定。

下面的special form def 创建了一个Var,如果Var不存在和没有给初始化,var就是不绑定的(不允许创建非动态的Var,必须显式指定根绑定):

user=> (def x)
#'user/x
user=> x
java.lang.IllegalStateException: Var user/x is unbound.

为根值初始化(如果存在,就被再次绑定)

user=> (def x 1)
#'user/x
user=> x
1
 

默认情况下(定义的时候初始化了根绑定),Vars是静态的(static),但是,建立动态Var的定义可以通过元数据标记的方式,然后在线程用时通过binding来指定。

user=> (def ^:dynamic x 1)

user=> (def ^:dynamic y 1)

user=> (+ x y)

2

user=> (binding [x 2 y 3]

         (+ x y))

5

user=> (+ x y)

2

 

binding被创建后其他线程是是不可见的。创建的binding可以被赋值,也就是在没有离开调用堆栈之前可以被上下文访问。可以在一块代码之前设置matadata标签:dynamic来指定:

user=> (def ^:dynamic x 1)

#'user/x

user=> (meta #'x)

{:ns #<Namespace user>, :name x, :dynamic true, :line 30, :file "NO_SOURCE_PATH"}

user=> (binding [x 2] (println x))

2

nil

user=> x

1

user=>

 

如果你想让函数编译为static的,并且指定返回值,可以看下面的例子(速度提升不少,关键的调用函数可以采用这种方式加速):

 (defn fib [n]   (if (<= n 1)

    1

    (+ (fib (dec n)) (fib (- n 2)))))

#'user/fib

 (defn ^:static fib2 ^long [^long n]

  (if (<= n 1)

    1

    (+ (fib2 (dec n)) (fib2 (- n 2)))))

#'user/fib2

user=> (time (fib 38))

"Elapsed time: 1831.113 msecs"

63245986

user=> (time (fib2 38))

"Elapsed time: 328.715 msecs"

63245986

user=> (meta (var fib))

{:arglists ([n]), :ns #<Namespace user>, :name fib, :line 1, :file "NO_SOURCE_PATH"}

user=> (meta (var fib2))

{:arglists ([n]), :ns #<Namespace user>, :name fib2, :static true, :line 4, :file "NO_SOURCE_PATH"}

user=>

 

在上下文中可能需要重定义静态变量,从Clojure1.3开始提供with-redefswith-redefs-fn这两个宏来修改。

定义函数的defn也是Vars的存储方式,也可以在运行时被重定义。这也为aop编程带来很多方便,例如:你可以封装一个类似logging函数给调用的上下文或者或者线程。

 

(set! var-symbol expr)

将Vars指定为special form

当地一个操作符为symbol的时候,它必须是全局变量。当前线程绑定的值就是后面的expr,也就是说必须是Thread-local的才可以,否则将会抛出一个使用set!来设定根绑定变量的错误。变量的表达式expr必须有返回值。

注意,你不能赋值给一个函数的参数或者本地绑定,只能是java的字段Vars Refs和Agents,因为这些数据在Clojure里可不变的。

使用set为java字段设置值,可以查看 Java Interop.

 

Interning

命名空间维护了每个Var对象的全局符号映射。如果使用def定义变量没有在当前的命名空间找到该符号,就创建一个,否则使用现有的。创建或者寻找的过程被称作interning。这就意味着,除非Var对象取消映射,否则Var对象每次被查询,所以请在循环中千万不要引用Var的全局变量,否则将非常慢,通过let或者binding让全局变量取消映射来提高速度。命名空间在Evaluation中构建了全局环境,编译器也把所有free symbols当做Vars来解析了。

可以使用阅读宏(Reader)#’来得到Var对象的内部的值。

 

Non-interned的类型的变量

可以通过with-local-vars来创建non-interned类型的变量,在free symbol解析的时候将不会被发现,这些值只能被手工的访问,但是也可以用作当前线程的变量。

user=> (defn factorial [x]

         (with-local-vars [acc 1, cnt x]

           (while (> @cnt 0)

             (var-set acc (* @acc @cnt))

             (var-set cnt (dec @cnt)))

           @acc))

#'user/factorial

user=> (factorial 7)

5040

posted @ 2012-07-31 01:48 steven.cui 阅读(1462) | 评论 (0)编辑 收藏

原文章写在Google Groups thread里,但是还是值得再说下。

有朋友把Java和Clojure的一些代码片段放在Clojure Google group里比较,并提到Java的性能要比Clojure快太多了,疑问到底Clojure能不能赶上Java?

在我的一个开源项目clj-starcraft中,关于java的性能问题,实际上也是我始终面对的,在我写这篇文章的时,我的Clojure代码还是慢了Java代码6倍(Clojure花了70秒解析了1050个文件,Java则只有12秒)

然而,70秒对过去的速度而言不算太糟糕,在刚开始的时候,竟然花了10分钟来分析1050个文件。甚至比我用Python实现的还要慢。

感谢Java的profiler和热情的Clojure朋友,下面列出了我在提升Clojure性能方面的一些tips:


(set! *warn-on-reflection* true)

这恐怕是最重要的一个提升:打开这个设置将会警告你在任何一处用到Java反射API的方法和属性。如你所想,直接调用永远比反射要快,不管哪里Clojure都会你不能解析这个方法,你需要自己用type hint方式来避免反射调用。关于使用type hint,Clojure官方站点给了一个如何使用和提速的例子。

修复所有关于*warn-on-reflection* 的编译警告后,我的clj-starcraft从10分钟降到了3分半。


强制设置数据类型

Clojure可以使用Java的基础数据类型,无论何时在循环的时候,坚决考虑将你的值强制转换成基础类型,这将大幅提高你的性能。基础数据类型在Clojure官方网站有例子和如何进行强制转换来提高性能。


使用二元运算符

Clojure可以在一行里面支持多个表达式,但对于运算操作符,只有在两个的时候才被inlined,如果你发现自己的运算符已经超过了两个,或许该考虑重写你的代码让操作符显示的成为两个。下面请看两者之间的比较:

user> (time (dotimes [_ 1e7] (+ 2 4 5)))

"Elapsed time: 1200.703487 msecs"

user> (time (dotimes [_ 1e7] (+ 2 (+ 4 5))))

"Elapsed time: 241.716554 msecs"


使用==代替=

使用==比较数字来代替=,提升性能那是相当明显:

user> (time (dotimes [i 1e7] (= i i)))

"Elapsed time: 230.797482 msecs"

user> (time (dotimes [i 1e7] (== i i)))

"Elapsed time: 5.143681 msecs"


避免vectors的destructing binding

在一段循环种,如果你想为了提升可读性从vector中传出值,考虑下标访问来代替destructing binding。虽然代码看起来更清晰,但却非常慢。

user> (let [v [1 2 3]]

        (time

         (dotimes [_ 1e7]

           (let [[a b c] v]

             a b c))))

"Elapsed time: 537.239895 msecs"

user> (let [v [1 2 3]]

        (time

         (dotimes [_ 1e7]

           (let [a (v 0)

                 b (v 1)

                 c (v 2)]

             a b c))))

"Elapsed time: 12.072122 msecs"


优先使用本地变量

如果你需要在循环中查询一个值,你或许需要考虑使用本地变量(通过let定义)来代替全局变量。看下两者的时间对比:

user> (time

       (do

         (def x 1)

         (dotimes [_ 1e8]

           x)))

"Elapsed time: 372.373304 msecs"

user> (time

       (let [x 1]

         (dotimes [_ 1e8]

           x)))

"Elapsed time: 3.479041 msecs"

如果你想使用本地变量来提升性能,可以考虑下面比较土的式的方式来避免全局变量:

(let [local-x x]

  (defn my-fn [a b c]

    ...))

使用profiler工具:

JVM有两个profiler工具, -Xprof和-Xrunhprof,找到程序瓶颈而不是瞎猜。


最后说明:

你已经注意到,在这些性能提升中,通过调用百万量的执行来提升了几百毫秒的性能。所以,不到万不得已需要提升性能的时候,没必要让你的代码看起来不够清晰。

原文地址: http://gnuvince.wordpress.com/2009/05/11/clojure-performance-tips/

最后补充:可以通过指定编译为static方法来提高性能:

pasting

 

(defn
  ^{:static true}
  fib
  [n]
  (loop [a (long 1) b (long 1) i (long 1) r (list 1 1)]
    (if (== n i)
    r
    (recur b (+ a b) (inc i) (conj r (+ a b))))))

 

 

posted @ 2012-07-29 14:15 steven.cui 阅读(1912) | 评论 (2)编辑 收藏

第4章  利用右脑


人应该努力学习洞察和培养自己内心深处的灵光一现,这远远胜于外面流光溢彩的整个世界。然而,人总会下意识地抛弃自己特有的想法,仅仅因为那是他自己的想法。

——拉尔夫.瓦尔多.爱默生(1803-1882)


启动感官输入:

     研究显示,使用多感官技术可以让学生的学习效果提高5倍,目前我本人见过的电子产品ibooks2 已经算是图文声并茂的最棒的学习产品了,也许以后全息技术的普及将带来所有电子感官输入和交互的一场革命。

     当你困在一个乏味的电话会议或者思考一个棘手的问题时,把玩下回形针或者晚些触觉游戏能缓解疲劳。

     增加感官体验以促进大脑的使用。

     在这里作者推荐不是使用商业工具(UML或者类似的东西)直接创建或者记录设计和架构信息,而是通过积木,乐高积木等等来增加感官输入。

     为什么这样做呢?实际就是刺激你的大脑,大脑总是渴望接受这种额外的、新奇的刺激。另外作者提到,团队成员可以进行角色扮演,试试吧,无意中你可能会想到xx的几句话真是让人捧腹,但你却对这个过程记忆犹新,比你写上去的或者总结下来的文字要强好多倍。


用右脑画画:

     绘画既是观察。

     绘画是一种R型活动,共享总线被占用,如果你进行的L型活动,同时R型就必须停止。很多休闲活动都能够激活R型停止L型的占用:听音乐、绘画、静思、慢跑、针线活、攀岩,等等。

     角色扮演:

     书中有个角色扮演的例子,有兴趣的可以去看《项目管理修炼之道》,琳达.莱辛描述了扮演的另一个用途:培训团队。在向团队介绍一种新框架的次数屡遭经历之后,她和同事大卫.得拉诺决定在下一个团队中用表演来模拟框架。这次,开发人员不再抱怨没有听明白,而是抱怨表演简直浪费时间,因为演出的内容简直是“太简单了!”

     这是因为角色扮演真的有效果

     认知转变,感受R型

     《用右脑绘画》,或者叫《像艺术家一样思考》,来自作者的推荐


促成R型到L型的转变

     去攀岩吧

     罗扎诺夫教学法(谷歌搜索:罗扎诺夫的音乐暗示学习法)

     酒酣写作,酒醒修改(R型先行,L型做整理)

     结对编程(一人L型,一人R型),结对编程每个程序员都应该尝试

     隐喻相同(抽象与具体事物互相融合,尝试将复杂的计算机用形象化的比喻将给不懂的人,你可以玩玩魔方,实际能恢复不难,转得快需要很长时间的联系,本人没有继续研究下去的勇气,但尝试了恢复的乐趣,是个很有意思的过程)

     并列参照系(随机并列,也许两个想法相隔十万八千里,你却能将其并列起来。例如,香烟和交通灯可以引出这样一个概念:在香烟上使用红色标志区来作为帮助戒烟的提示。)

     系统隐喻(隐喻思维是编程的基础,因为它存在于所有的抽象思维中)

     讲个笑话吧(幽默既不是浪费时间,也不是无害的消遣,而是反映了思维、学习和创造所必须的重要能力。它与联系有关。培养幽默感以建立更强的隐喻)


收获R性线索

     你已经知道

     你是否曾经听到电台里播放的一首老歌,然后在若干天突然想起歌名或者歌手?你的R型思维一直在背后异步地思考这个问题,直到最终找到相应的记忆。

     伊莱亚斯.豪的奇遇


 

     在1845年,一个名叫伊莱亚斯.豪的美国人尝试发明一种实用缝纫机。进展不是非常顺利。在经历了漫长、艰苦、一无所获的一天之后,晚上他做了一个非常可怕的噩梦,在尖叫中惊醒,直冒冷汗。

     在噩梦中,他身处非洲,被饥饿的食人鱼绑架。他马上就要被扔进沸水里煮死。他努力挣扎,而猎手们就一直用一种看起来非常可笑的长矛戳向他。

     第二天他描述噩梦时说,他的注意力集中在“可笑的长矛”上。因为这些长矛的前端钩子上有洞,这就像是手持缝纫针上的洞,只不过后者是在末梢上。

     伊莱亚斯接着获得了自动缝纫机的第一份美国专利,这要归功于他来之不易的灵感:缝纫机针的洞需要与平常的针持针方向相反。


     利用图像流

          1.观察图像,努力看清所有细节

          2.大声地描述出来(真正发出声音,这很关键)。

          3.利用全部五种感官想象它

          4.使用现在时态,即使该图像都溜跑了。


     利用自由日记

          写信是一种伟大的习惯。blog这种模式很受欢迎,wordpress或者blogspot(墙外)推荐。

     晨写技术

          早上起来第一件事情。

          至少写三页,最好不用电脑,如果使用电脑关掉所有跟写作无关的东西(只开evernote)

          不要审查删减你写的东西。不论是优秀的还是陈腐的,只管写下来。

          坚持天天写

     “自由写”技术

          开个blog,将你的想法随时记录,或者用evernote,保持随时随地可以自由写

     利用散步

          遇到问题的时候,试着找个安静的地方散散步,不要坐在电脑旁,离开键盘去解决难题。当你不寄希望于它时,就会发现答案自己冒了出来。


收获模式

     代码中的模式

          如果你不是一个特别在意编码排版的人,那我可以负责任的告诉你,你离真正程序员的路还很远,反而用lisp的人,更注意代码排版,看代码的时间远远高于你写代码的时间,如果你连代码都排列不好,问题自然避免不了。切记,你可以桌子混乱,实际是为了保持上下文不被切换,而代码却不能格式混乱,格式都混乱甭提逻辑了。


     换换脑子

          改变解决问题的角度,前面一章提到过,了解一只青蛙不是解剖它,而是如何创造它!


     神谕冲击的魔力

          在古代,教堂的大主教经常通过神谕求的建议。像大多数算命者或者占星师一样,神谕给予的响应或者信息通常非常模糊,就像谜一样。你不得不自己来“解释”它。这就是对大脑的一次冲击。

         作曲家布莱恩.伊诺和彼得.施密特提出了一套100种间接策略来换脑。去看:http://www.rtqe.net/ObliqueStrategies/



 

          例子:

               这项别的什么东西么?

               不做任何改变,坚持始终如一

               关上门,从外面听

               错误是一种潜在的提示(其实可能不是一种错误,一种形态)


     莎士比亚的谜语

          莎士比亚做过很多语言重造的工作:

               Full circle(绕圈子

               Method of the madness(貌似疯狂实则有理的行为)

               Neither rhyme nor reason(莫名其妙)

               Eaten out of house and home(吃的倾家荡产)


     在此,也感谢译者(崔康)对本书的给力翻译,没有对语言的融会贯通很难将两者联系起来,谢谢。


试一试:


          使用乐高积木做项目模块讨论。

          使用双人机制,让同伴激励你,讨论你的进展。

          使用隐喻描述你当前的项目。

          观察你认识的专家,看看他们有什么“奇怪”的习惯让你觉得更能理解?

posted @ 2012-07-10 01:21 steven.cui 阅读(358) | 评论 (0)编辑 收藏

第3章  认识你的大脑

我们的大脑就是双CPU,单主机设计总线。




1号CPU即线性的,也称为L型处理模式或者叫思考模式。程序员大多喜欢step by step这种方式,一步步的去线性处理。

2号CPU是非线性的,也称为R型处理模式,更多的是直接和创造性,但两者之间访问内存(大脑)的时候,都是互相抢占系统总线的。


你的记忆更像是全息影像方式在存储,在我刚上午看过的书,下午可能就忘记了,但是我看到什么位置竟然是书中的插图提醒的我。人们对图像和声音的记忆更强于文字,L型记录的是一些循规蹈矩,有规律可循的记忆,而R型则是突发奇想,在你不经意间(睡梦中,洗澡时等等)想到了一个解决方案,R型是异步的,并且有时候是你不经意间,而不是刻意去想就能联系到另外一件事情上。


随时随地记录你的想法


     作者的推荐: http://www.pocketmod.com

     语音备忘录/信箱

     Fisher Space钢笔

     Moleskine笔记本


我本人推荐:

     你应该有个tablet/pad(我个人推荐ipad)

     你需要一台不错的智能手机可以跟你的电脑或者pad进行同步,iphone? 还是android都可以,屏幕至少4.0寸以上

     软件方面:EverNote, GoodNotes,Penultimate,OmniFocus,Mindjet, AwesomeNote等等。


我们每个人都有好点子,可真正付诸实践的却少的可怜。



L型和R型处理方式的特点

     L型:

     处理令人感到舒适、熟悉而放松,提供以下九种能力:

  •      语言能力
  •      分析能力
  •      符号能力
  •      抽象能力
  •      时间能力
  •      推理能力
  •      数字能力
  •      逻辑能力
  •      线性思维能力

     R型:

     非语言性的,喜欢综合学习,集成事物形成整体。

  • 非语言
  • 综合
  • 具体
  • 分析
  • 非理性
  • 空间性
  • 直觉
  • 全面

R型思维能力是很难衡量的,至少比起L型来说要难的多。R型思维更是一种综合,大局观的体现,也是一种逆向思维和想象力,创新能力的体现。我个人推荐程序员应该至少了解一门艺术,例如绘画、摄影、音乐啊等等,这些是R型非线性思维给与你的灵感和想象力,并且会给你犹如突发奇想这样的奇迹,我们了解一种事物不是通过逆向倒推来了解他,而是通过它是如何出现和创造的而去想如何构建它。我个人推荐,无论学什么至少应该去了解这么技术或者艺术的诞生历史,为什么如此产生的,为什么会有这样的想法,想法和初衷是什么?


作者给出一个很精辟的理论:真正想要了解一只青蛙,传统的解剖不是办法,更好的方式是构造一只青蛙。


综合学习与分析学习并重。


设计胜于功能

     无论什么产品,面向的终端用户都需要理解你的产品。苹果的ipod的广告上从来不说能容纳多少个G,一个G等于多少多少字节,这样用户会疯掉,谁会听你扯淡这些他们不理解的东西,他们只需要知道能存放多少首歌曲罢了。


吸引力更有效

     吸引力的界面比不具有吸引力的界面更易于使用。尽最大努力争取好的设计,它真的很有效,好的设计也是需要不断修改出来的。

     美来自于选择——路易.康,对于一个程序员来说,好的设计很多都是构建于各种选择(开源稳定的组件),基于某种设计理论SEDA,CELL等等。


R型看森林,L型砍树木

     如果你想发现全局、整体的模式,你需要R型,如果你需要分析部分和细节,你需要L型。讲述一个程序员看开源项目的例子,在拿到一个开源项目的时候,下面几个步骤开始:

  1. 了解开源想的初衷和目标,解决了什么问题,把握这个开源项目的方向性。
  2. 开始了解开源项目的大致结构(导出UML图,或者大致浏览项目的接口文件),以及开源项目中依赖的组件。
  3. 有了整体全局观以后,下来试验下开源项目提供的tutorial。
  4. 开发调试并亲手实践一个例子,对整个流程有个具体把握。
  5. 尝试在开源项目上进行你自己项目的试验和业务逻辑:
    1. 构建一个具体的业务逻辑。
    2. 。。。。
    3. 。。。。
    4. 。。。。
  6. 回头再来看一些代码,这样实践相结合,更容易理解。


训练自己的大脑

     程序员大多数都显得死板和缺少R型思维能力,学习一些新鲜的事物,可以看看科幻电影或者小说等等,增加自己的想象力,想象力来源于生活,而生活却是无所不包,包罗万象的百科全书,你甚至可以说任何的发明都是来源于生活,唯有热爱生活的人才能做出好产品,产品也许不需要你创造,只是在选择不同的组合。

posted @ 2012-06-19 22:40 steven.cui 阅读(728) | 评论 (0)编辑 收藏

 

 此读书笔记并不完全作为阐述想法,所以在阐述一些问题的时候可能没有前因后果,更是一种总结性的话语和书上言语的精华,这有点悖论,如果你想了解,请去看《程序员的思维修炼》,这本书可以跨学科,即便你不懂程序,都值得一看,是从思维和大脑层面来开展介绍的。

 

2 从新手到专家的历程

 

     新手到专家需要经历5个阶段(德雷福斯技能获取模型

     真正的专家不怕考验,而轻松面对~

     真正的专家很难将自己的行为解释清楚,而熟练到已经无意识了。

     

     新手:在乎自己是否能成功,不知道自己是对是错,不是特别想要学习,只是实现一个立竿见影的目标,不知道如何应付错误,错误出现不知所措。新手需要指令清单,有规则,有顺序。但规则只能让你启程,不会让你走的更远。

     高级新手:高级新手不想要全局思维,当公司在展示全年销售测量表和数据时,你可能不感兴趣,可这预示着明年你在这家公司是否还能继续干下去。但是,你看不到这种联系,因为你层次还不够,只处于较低的技能水平

     胜任者:可以独立解决自己遇到的问题,并开始考虑如何解决新的问题。处于这样水平的人通常具备主动性足智多谋,往往在团队中发挥着领导作用,他们是团队里的好人,但缺乏足够的能力——自我反思和纠正。

     精通者:精通者需要全局思维,而且需要更大的概念框架,过于简单化的信息,他们会非常沮丧。在精通者中,最明显的特征:自我改进和反思。同时他们善于倾听别人的意见,并从那些失败或者成功的项目中认真观察、学习和总结。

     专家(大师):专家凭直觉工作,并不需要理由。他们有丰富的经验,并能家当运用,他们著书、写文章、做演讲等等。专家往往通过观察一些细节(可能常人根本无法觉察到的一些细节)就能判定特征和问题所在,那些无关紧要的会自动过滤更是专家具备的能力。

 

实践:

你不知道自己不知道

             达尔文:无知往往来自于自信而不是知识

 

上面两句话,刚开始理解的时候没有突然顿悟的感觉,但跟媳妇一番讨论后,更加理解了:

学生问老师自己所掌握的知识到底有多少?

老师给出了下面的回答:

你现在的知识就仿佛是一个点,而老师比你要多一些,是个圈,老师知道你不知道的,你有可能知道自己不知道的而老师知道的,你通过学习将来会知道老师知道的,然后超过老师去知道老师不知道的,老师也在不停地学习,但随着知道的越来越多,也就意识到自己不知道的越来越多,因为越大的圆外面就会有更大的圆。

             

达尔文的总结,一语道破了无知的自信(无知者无畏这句古话更是说明了假自信),潜意识层面根本就是不知道自己不知道。有时候自信也很可怕,因为你要确认自己到底是否真的知道。

 

大师都是凭直觉办事,可公司更希望通过数据或者规则来确定事情是否是对的,这种方式试图在毁灭"专家,公司往往轻视专家的直觉,认为这是不科学不可重复。新手使用规则,而专家使用直觉,具备元认知能力metacognitive),或者叫具备自我认知能力的人往往出现在较高层次中。

知道你不知道什么

专家!=老师,教学是一门技能,你在某个领域是专家,但这并不能保证你可以将它教给别人。

 

     有效地使用德雷福斯模型

     十年磨一剑,也许需要一辈子或者更长?学漫漫路漫漫,我们需要积极实践自己:

      需要一个明确定义的任务

      任务需要有适当的难度——有挑战性但可行

      任务环境可以提供大量反馈,以便于你采取行动

      提供重复犯错和纠正错误的机会

      一旦你成为某个领域的专家,在别的领域成为专家就会变得更容易。你已经有了现成的获取知识的技能和模型构建的能力。

     软件开发的职业特征:

      程序员往往认为自己是一种工具,从而漠视工作,只是执行分析师的指令,而不期望自己对项目的设计和架构有所创见。

      由于薪酬等级的不平等,专家级的程序员争先恐后的离开一线编码,通过管理、教学或者巡回演讲赚更多的钱。

      软件工程教育开始受到质疑。很多人认为正规的实践模式是最好的教育方法。这种对正规方法和工具的过度依赖削弱了实践中真正经验的作用。

           R&D精神(Rip off and duplicate, 偷学技艺/偷师学艺),我们可以从他们的工作中借鉴很多经验教训并应用到软件开发中。

 

     勇于承担责任:

      新手往往只是执行命令,新手过渡到胜任者最大的区别在于能独立解决问题
和承担责任。

      通过观察和模仿来学习(R&D)。如果你有孩子你会发现,他们很少照你说的做,而是大多时候在模仿你。

      模仿的同时就是实践的过程,没有实践就没有技能。模仿->吸收->创新

      保持实践以维持专家水平,全世界最优秀的那些专家没有因为做了20年以上开发而不去编码了,实践是保持技能的唯一手段。

     警惕工具陷阱:

     曾经,在我刚接触软件领域的时候,曾一度认为UMLMDA以及TDD是未来解决软件的必要良方,甚至也将其滥用,然而合宜的工具需要放到合宜的

     环境去运用,模型只是工具,而非镜子。如果你需要创造力、直觉或者独创能力,避免使用形式方法。

 

     再次考虑情境:

     高端的顾问最喜欢回答说:具体情况具体分析,当然他们是对的,他们的分析依赖于很多事情——所有那些专业人士懂得去寻找至关重要的细节,同

     时也忽略无关的细节。

     在系统思维中,如面向对象编程,往往是事物之间的联系最让人感兴趣,而不是事物本身。这也是面向对象化编程的特点,你大多数时候在想事物本身的联系,而实际问题的解决却放到了后面,本人的目前的理解是,面向对象编程真的有那么重要么?或许只是在某些方面比较重要罢了,扩展性和低耦合的确是面向对象的实践的目的,可除此之外纯为了面向对象而行动,就存在滥用倾向了。例如java这种语言的面向对象纯属为统一思想而设置的程序员枷锁。

 

     日常中的德雷福斯模型:

         新手需要快速成功和与情节无关的规则,而专家需要获得全貌。理想情况下,你希望团队里混合各种层次技能水平的人,拥有一个全部是专家的
     团队存在它的难处。当所有人在考虑森林的时候,你也需要一些人来关注一棵棵大树。

         学习如何学习的技能。

 

总结:

     了解自己出于德雷福斯模型中的哪个阶段,并自我评价,了解你的团队成员,他们的技能阶段,以及对你有何帮助。回顾曾经团队经历的问题,并运用德雷福斯模型解释这些问题,对于已知的问题是否能通过德雷福斯模型解决或者避免?

                         

 

posted @ 2012-06-17 03:08 steven.cui 阅读(440) | 评论 (0)编辑 收藏

java的多线程Thread类提供了setName方法或者通过构造器传入name,来指定线程的名称。

近些时间在开源方面看到Netty,观察到Netty的重命名线程的策略类:

ThreadNameDeterminer。这个接口有两个策略,一个是使用PROPOSED(建议名称),还有个是CURRENT(当前名称)

当前名称的策略是未实现的,可能为以后扩展考虑吧。

另外就是ThreadRenamingRunnable这个类,这个类里面构建函数传入Runnable接口,和proposed建议名称。

由于本身ThreadRenamingRunnable也是实现Runnable类的,所以你在自己业务逻辑种还是照样实现Runnable接口来写逻辑,完全对业务代码没有侵入。

代码中大概是这样的情况:

public run() {
     //根据规则把线程名字进行修改
     try {
          runnable.run(); // 调用传入接口的run方法
     } finally {
          if (renamed)
               // 恢复之前的名字
     }
}


只需要在构建的你的Runnable的时候,重新包装一下即可:

new ThreadRenamingRunnable(new OioWorker(acceptedChannel),

                               "Old I/O server worker (parentId: " + channel.getId() + ", " + channel + ')'));


这样的Decorator模式,重新将Runnable接口进行了“装饰”,使其具备了线程名称的功能。

Runnable接口还是原来的接口,对run方法的再次封装使其具备了另外一项功能,这就是Decorator模式的精华所在。

posted @ 2012-06-16 22:32 steven.cui 阅读(1132) | 评论 (0)编辑 收藏

判断一个数是否是2的n次幂

类似这样的数字

1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 …


if ((n & -n) == n)

1 public class Is2Power {
2      public static void main(String[] args) {
3           for (int i = 0;i <= 1024; i++) {
4                if ((i & -i) == i)
5                     System.out.println(Integer.toBinaryString(i) + ", " + Integer.toBinaryString(-i) + " " + i);
6           }
7      }
8 }

posted @ 2012-06-16 22:26 steven.cui 阅读(623) | 评论 (0)编辑 收藏

业务上线后,在有大量并发后,出现了一个线程完全被占用的问题,后来通过得到jvm堆栈信息(kill -3)看出来是死锁问题。

由于业务逻辑代码实在比较复杂,此处滤掉业务代码把线程竞争关系展示出来:

1线程———>获得A锁———>获得B锁———>释放B锁————>释放A锁

2线程———>获得A锁———>释放A锁

3线程-——————>获得B锁———>获得A锁


问题就出在1和3线程之间的AB锁嵌套导致死锁问题,1线程在没有获得B锁的时候,3线程开始获得B锁然后又得到了A锁,这时候就完全释放不了A锁了,死锁产生了。

由于时间关系,问题是理清楚了,只要删掉1线程的A锁就可以了,当时还是仔细了解过是否删除1线程A锁,发现对业务A锁是没必要的。但是线程2会不会也会像刚才一样产生线程死锁呢?不会,因为线程2里并不会得到B锁。

1线程———>获得B锁———>释放B锁

2线程-——————————>获得A锁————>释放A锁

3线程———>获得B锁———>获得A锁————>释放A锁————>释放B锁


问题是死锁,但暴露了两部分问题:

1.过早的认为自己能控制好竞争关系,对线程间的竞争过早的做出了判断

2.每多设计一个锁就增加了一个竞争的因素,尽量小心,一个锁就有可能是一个地雷,一不小心就可能导致严重的问题。


《java并发编程实践》这本书中介绍过LeftRightLock,详细了解这个问题的朋友可以去查下这本书的第十章 避免活跃性危险

此书极其详细的介绍了LeftRightLock出现的可能,有可能是因为自己编写程序的疏忽导致,或者由于对锁的认识不足导致,诸多原因都能找到解释。

posted @ 2012-06-16 22:22 steven.cui 阅读(482) | 评论 (0)编辑 收藏