程序员的创新修炼

  以系统的方法来理解创新思维的基本方面有助于了解持续创新的内在规律。本文作者根据多年的工作体验和思考,展现出了一个循序渐进的创新思考模型,并结合实例进行了深入的阐释和分析。
 
        关于创新
 
        对程序员来说,“创新”是一个永恒的话题。它给世人的感觉是既简单又玄妙。说它简单是因为创新似乎不需要严格的外在条件,说它玄妙是因为我们很难说清楚创新产生的过程,所有的创新几乎都是不可复制的。
 
        【实例分析】前几天听到同事在抱怨没有足够的硬件资源做伸缩性测试,经过进一步询问,我了解到:产品中有一个部分需要多任务(进程)执行;任务 进程原本是由 C++ 实现的,为了调用第三方 Java SDK 远程访问 WebService,每个进程都加载了一个 Java 虚拟机。经过测试发现使用了此 SDK 的 JVM 占用了大量的系统资源,最终大大降低了系统的可伸缩性。面对同样的场景,人们的反应会有很大的差异:有些人会抱怨几声了事;有些人会设法寻找更为强大的机 器;还有人会尝试从软件架构的角度改变现状。例如,把通过 Java SDK 远程访问 WebService 的逻辑封装为本地代理服务,它可以将相关业务逻辑的重用从组件级提升为应用级(如图 1 所示)。没错!这就是创新。本文将放弃任何对结果的讨论,因为创新不应以成败论英雄。
 

 
        如果说这些微创新不但是每个程序员都可以做、而且必须要做的工作,那么我们是否已经准备好了呢?这方面的系统论述向来是比较少的,水平思维理论 的缔造者和倡导者德·波诺教授在《比知识还多》一书中提出了一系列可用于提升思维创造力的工具(例如,通过随机输入突破现有思维模式、挑战概念、跳出主要 观点、定义问题和剔除错误等)是这当中杰出的代表。在我看来这些工具并不是独立的,它们相互影响、共同发挥作用。接下来就走近它们,以探其真面目。
 
        批判性思维
 
        批判性思维是创新过程最显著的特征(也就是剔除错误),就让我们先从它开始吧。
 
        在程序员江湖闯荡久了,就会深知创新的艰辛。不求一鸣惊人、但求独善其身是程序员队伍中一种比较具有代表性的思潮。我们真正能做到独善其身吗?试想如果现有代码的可维护性很差,任何人都很难在有限的时间内写出高质量代码,最终很可能落得个同流合污。
 
        有时我们也会一不小心走到另一个极端:如果留意,我们总能在公司的茶水间里听到员工关于公司缺乏产品创新的恶评。批评是有益的,但我们更需要批 评过后的冷静思考和实际行动。创新无疑需要批判性思维,但前提是我们能将“批判”与“批判性思维”区别开:批判的目的只是为了达到对某个事物的否定;而批 判性思维则是通过否定来寻找更好的做事方法。单纯的批判是消极的;而批判性思维则要积极得多。
 
        问题的定义
 
        批判性思维是建立在问题定义基础上的,因为“没有问题就无所谓批判”。
 
        什么是问题
 
        什么是问题?期望与现实的落差就是问题。现实是容易觉察的,但界定外界期望就难得多了。人们倾向于把外界的输入作为建立合理预期的唯一标准,而 不是独立形成自身对预期的认识。例如,开发人员总乐于将测试人员在缺陷描述中记录的期望行为和结果作为实际的用户需求,并据此来修改代码。
 
        【实例分析】某产品中定义了“策略”的概念,并提供了相应的编辑界面。在策略编辑界面(如图 2 所示)中,允许用户对原有策略进行保存或另存为一个新策略。测试人员曾经报过一个用户体验方面的缺陷:用户在选择“另存为”功能时,很可能会遇到系统提示 的失败报告,原因只是忘记了修改策略名称。
 

 
        我们可以顺着测试人员的思路将问题定义为“如何让用户避免令人沮丧的失败报告”。进一步思考,不难发现策略编辑界面还有其他问题, 比如,用户 原本希望创建一个新策略,却错误地点击了“保存”按钮。因此,也可以将问题定义为“如何通过合理的功能布局,避免不能预期的用户行为”。最后,我们决定提 供一个“策略拷贝”的新功能,并将“另存为”按钮从策略编辑界面中移除。
 
        在定义问题时,我们需要注意以下几点。
 
  • 一个现象可能隐藏着多个问题。
  • 区分核心问题与非核心问题;可以存在多个核心问题。
  • 问题可以在不同抽象层次上定义(从用户体验的角度来看,可分为表现层、框架层、结构层、范围层和战略层)。
        随着被灌输信息的增多,人们所受到的来自外界的影响和约束不断增强。一个人对现实的接受程度越高,问题形成的难度就越大。
 
        外界是不完美的
 
        对于软件研发团队,定义问题的能力直接影响其需求分析的质量,进而最终决定了产品的质量。一般认为软件工程师参与到需求分析与产品设计的机会并 不是很多,他们接收来自用户或者产品经理的需求规格,并且努力把功能列表转变为可以运行的程序。不幸的是,现实中软件生产过程要复杂得多:在开始阶段,写 下来的需求只是冰山一角;未写下来的需求才是沉浸在水下的巨大冰块;即使写下来的、被用户所确认的需求规格也不能确保最终一定能够让用户满意。
 
        《用户故事与敏捷方法》在论述用户故事与需求规格、用例等传统需求分析工具的区别时,特别强调用户故事的目的不是记录客户与开发团队之间的协议或契约,而是充当着用户具体需求对话的占位符。
 
        因此,我们不能把产品经理的输入等同于用户需求。在现实中,开发团队总是容易认为项目早期形成的用户故事就是对用户需求的描述,因此大部分人都 放弃了对问题进行深入且持续的思考。敏捷实际上是想告诉我们:外界是不完美的,所有相关人员(产品经理、开发者、测试者、用户、文档编写者等)只有通过不 断的沟通才能加深对用户需求以及产品策略的理解,并在讨论的过程中达成一致。如果我们不能在这个方面放弃传统的惯性思维,我甚至怀疑所谓的敏捷是否还具有 生命力。
 
        外界的不完美导致我们必须关注自身定义问题能力的培养。首先,通过独立的思考形成自己对一个事物的预期,而不是唯命是从;其次,通过各种可能的 手段来确认这个预期是否合理,并进行必要的修正;最后,对比现实与预期形成对问题的认识。当这种思维模式成为你的一个思考习惯时,问题就会不断地从脑海中 涌现出来。
 
        概念的建立
 
        建立概念模型的意义
 
        合理预期是建立在合理的概念模型基础上的。只有明确了概念,才知道未来的路该往哪里走,才知道什么时候需要坚持原则、什么时候需要像现实妥协。只有建立起概念模型,你才有可能进一步思考现实与存在于你脑海中的概念是否一致。
 
        每一个软件设计问题的背后都隐藏着一个或简单或复杂的概念系统。很多时候,软件工程师并没有意识与能力去主动地发掘这些概念,这是导致软件设计不确定性的重要原因之一。因此,对概念的驾驭能力就成为软件架构师最为倚重的基本能力之一。
 
        忽视概念的历史根源
 
        对概念的忽视有其深刻的历史原因,如下所述。
 
        炒作概念。不知从什么时候开始,“概念”常常与一个动词相关联,它就是“炒作”。一个新产品往往借助炒作热 门概念来提升自身的价值,“概念”渐渐变成了假、大、空的代名词。这与概念本身的功能完全背道而驰——概念原本是为了让一个或一类事物能够更准确地被大众 以一致的方式所理解。说句公道话:“之所以盛行炒作概念之风,不是因为今天概念太多了,恰恰是因为现如今人们缺乏对概念的理解。”这一切大概发生在过去的 十年里(十年前的我大约刚刚完成学业、步入社会)。
 
        只摸石头不过河。我们不妨把时间推得再久远一些:在我念书的年代里,对概念的深入研究变成了教条与迂腐的代 名词,因为对很多人来说概念意味着陈旧,意味着一成不变。概念确实表现出一定程度的稳定性,这种稳定性源于其抽象的本质。但我们切不能将这种稳定性绝对 化。概念同样也会像这个世界上的绝大多数物质一样,随着时间的流逝发生变化。这种可变性源于其主观的本质。没错!概念并不是像人们想象的那样客观。人们只 是试图通过自身的努力将自己对概念的理解无限趋近于客观。
 
        “实践是检验真理的唯一标准”—这是几乎每一个中国人都熟知的一句话。我从不怀疑其合理性,但放在上述社会环境中,难免容易让人迷失:既然是 “检验”,我们就应该首先澄清待检验对象。换句话说,我们应先形成对真理的假说,然后不断地用实践结果增加其可信程度,亦或反之。现实中,人们渐渐丧失了 事先形成对真理认知的耐心,这种不耐烦也许是源于人们对于可能出现的自我否定的恐惧,这直接导致实践最终仅仅成为一些人收集数据的工具。
 
        我曾与一些软件研发人员讨论有关软件性能测试的问题。我发现他们并不能清楚地说出某个测试的目的。当我进一步询问测试结果能否帮助我们得出一些 结论时,他们就变得含糊其辞。在我看来:单纯为收集数据而进行的测试是毫无意义的,这就好比只惦记摸石头而忘了过河才应是原本的目的。
 
        缺少点科学精神。曾经的诺贝尔奖得主杨振宁在对比中华文化与近代科学时,有如下精彩总结:中国传 统    文化所追求的“理”与近代科学所追求的“自然规律”方向上一致。但它们在求“理”的方法上是不同的。传统中国文化主要依赖归纳法求理,这里面没 有逻辑与推演;而近代科学除了使用归纳法以外,更依赖演绎法。
 
        显然,对于建立复杂的科学体系而言,演绎法更高效。这就不难解释:为什么自然科学在近现代中国更多是以舶来品的形象出现?演绎法需要逻辑,而逻辑建立在概念的基础之上。如果缺少这方面的先天基因,那么就更需要后天努力了。
 
        乐观精神
 
        没有精神层面的支持,创新是无从谈起的,因为创新实在是一项艰巨的工作:概念的建立不是一蹴而就的,需要反复的推敲、对比、自我否定;问题的定 义更是自我意识游走在理想与现实之间,尝试各种问题边界的可能,不断地进行权衡;人生贵在坚持批判性思维,而不沦落于简单的批评与抱怨。所有这些行动都是 很困难的,因为它们会产生巨大的认知摩擦。由此可见,对于一个致力于创新的程序员,能够建立并保持一个积极的人生态度才是最值得庆幸的事情。
 
        当我请求同事们进行自我评价时,大多数人都会为自己打上乐观的标签,因为他们把乐观与快乐、自我满足等概念混为一谈。一般人通过努力可以让自己 维持一个相对快乐的心境,但要做到乐观就很难了。快乐是一中状态,而乐观是一种态度;快乐是相对短暂的,而乐观是相对持久的;快乐既可以源自内心,也可能 是源自环境,而乐观是一定是由内而外的。
 
        创新思考模型
 
        我们可以将创新模型简单地归纳为以下四个核心要素。
 
  • 创新需要挑战现状,即批判性思维(要素)。
  • 批判性思维需要准确的问题定义(要素)。
  • 问题的定义有赖于概念系统的建立(要素)。
  • 在初始阶段,概念模型的正确与否是次要的,更为重要的是要有一个概念模型,然后这个概念模型可以随着认识的深入而不断演化。谁在幕后推动认识的 发展?答案还是批判性思维。批判性思维有助于我们修正原有概念的不足或创建全新的概念,在思维的各个阶段都需要乐观的人生态度的支持(要素)。
 
        回到开篇的实例中,让我们看看这些要素是如何发挥作用的:我们不能接受过高的资源占用这个事实,即使是在硬件变得越来越廉价的今天,滥用系统资 源永远是值得我们去批判的。问题的关键在于我们如何将依赖于第三方 SDK 的业务逻辑(Java)从任务中物理地剥离出来。我们曾经探讨彻底消除对第三方 SDK 依赖的可能性,后来发现其成本太高。组件级重用与应用级重用是在建立对问题定义的过程中很重要的两个概念,典型的应用范例是微软将二进制组建模型从 COM 升级为 COM+。SOA 是另一个发挥重要影响的概念,我们将业务逻辑封装为本地服务代理,并以标准的方式暴露其接口(WebService)。
 
        结束语
 
        以系统的方法来理解创新思维的基本方面有助于我们了解持续创新的内在规律。上述分析结合了我近几年的工作体验与思考,并试图展现出一个循序渐进的创新思考模型。创新思维之复杂原本不是我所能涉及一二的,但最终还是决定把目前的认识提出来,作为大家进一步讨论的起点。
 
        关于本文的论战
 
        周爱民
 
        作者意在讨论方法论本身,而非某一具体的方法。从这一点来看,作者的逻辑是:创新需要批判,批判需要问题,问题需要概念模型;概念是从对认识的 持续批判中得出、修正与进化的。那么在这一逻辑中,所谓“创新”不过是一个具体方法的结果,甚至是对具体结果的修饰而己。作者对方法论的讨论未能最终落足 于“如何‘认识’一个系统”,而是趋向于迎合读者口味地去强调“创新”,这是本文的一大弊处。但文章总体的可读性、系统性仍是可供读者品评的。
 
        许正华
 
        对于周爱民老师给出的点评意见我基本上同意,除了关于迎合读者口味地去强调“创新”的评价,至少它不是我的本意。我想讨论的是创新思考的方法本 身,而不是创新的结果。现实中人们更关注于结果,而忽视了创新性思考其实只是若干可以被训练的思维方法中的一种。创新本身并不神奇—就像人们在谈论所有天 才那样,如果我们也能够看到他们艰辛的成长道路与所使用的先进训练方法,就不难理解“其实天才也是可以培养的”。
posted @ 2012-05-18 16:42  你看起来很好吃  阅读(545)  评论(0编辑  收藏  举报