零碎: 学习, 技术明星, 面向对象

没发帖, 不代表完全没有想说的. 鉴于时间紧, 任务急, 有预感高产期又要来了, 暂时不像过去那样长篇大论了, 就几个点说说.

首先要说的, 大家少上点网吧. 这些天上网条件受限, 一下子效率高了很多. 这事我想不用多说了, 大家心里都很清楚自己的状况. 这里头就涉及到获取资讯和学习两方面的问题. 我在这里要说的是, 借口, 全都TM的是借口. 比如那些IT新闻, 看似很重要, 尤其是对一些象我一样目前主要做Web的同志, 其实真的不可或缺吗? 明天Google/MS就推出了你潜心研究了大半年的产品, 而你还在alpha, 都不好意思放出来预览, 那你就不做了? 又如果你发现了什么别人的想法, 可以融合到自己的产品中去, 你就马上又重新设计? 这恐怕和过去接项目的时候, 需求不停的变快差不多了.

学习的方面. 学习总是不能停止的. 不过我的一个体会是, 必须知道目前的知识是不是已经足够覆盖全部技术需求. 我们不可能Linq出来改一次代码, SilverLight出来又换一个实现. 举个例子, 最早我根本不会用反射, 有一天在网上看见了相关文章, 觉得这玩意好使. 当时我们的系统里有很多需要共享的对象和数据, 直接加锁, 这和我的设计理念不合(因为这个对象也许换个场景就无需加锁, 比如可以在一个更外部的拥有者身上枷锁). 我想大家都知道Hashtable处理lock的方式, 这是一个经典教程, 而Java和.NET都是这么实现的: 继承下来搞个同步代理, 象Anders说的和他想致力消除的一样, 这些实践过程里充满了繁文缛节.

于是呢我就学了一天反射, 第二天实现了动态生成代理, 配合Attribute或者描述配置, 用Sync<T>.Synchronized(T obj)这样的方式. 2天时间没了. 那么这个动态代理一共用在几个类上呢? 2个. 因为只有两个类还没有手工写过做同步用的代理. 而十几个类的同步代理, 手写也只需要一两个小时. 既然有了统一的方式, 就怎么看着原来的手写代码不爽, 最后把所有类手写的同步代理去掉, 全都改成使用那个动态生成. 测试, 整理代码, 又好几个小时出去了.两天的时间看着不多, 不过这边两天那边两天, 时间怎么没的? 学习要找对时候, 如果避免不了诱惑, 不如不学.

不过, 我说过, 我是个刚刚入门的水准, 什么叫入门? 说白了就是, 具体技术, 比如反射这类, 看我的状态, 学习起来只花一些实践和记背的功夫, 除了我身体素质和精神状况所带来的限制, 不会有任何困难. 你可以拿我这个标准, 去衡量一下你自己, 不过别自己骗自己, 就我的经验, 很多程序员在学习能力上锻炼还不够, 远没有自己想象中强; 尤其是搞不清一个东西的学习成本. 知识经常是连带性的, 看着简单, 靠就这么个玩意, 结果浪费了很多时间也不能把一个知识点掌握到足够实践. 我较早时学习设计模式就是这样, 因为那时候没有入门, 却觉得不过是些方法嘛, 好掌握, 结果吃了很大亏, 走了很多弯路.

如果你达不到这个入门的标准, 在学习上可能会浪费很多时间, 是不是不学了呢? 这个我觉得倒是相反, 我说过, 一个程序员要是不如我, 那真该努力了, 没入门的程序员一文不值. 哪怕把工作耽误了, 也得给自己留出时间去学习, 只有在学习的过程中才能掌握学习的诀窍, 最后形成一个加速度. 耽误工作, 对老板不负责, 不过等你入门了, 甚至走上专家之路, 你能回报给老板的(虽然可能是另一个老板了)要比一个没入门的人多的多, 最终你这些能力会用到社会生产力上(虽然可能仅是一个小角落, 还不是直接的), 那么牺牲一个老板的一个项目, 是值得的.

当然, 我自己不推崇这样办事, 想学习可以脱产可以要求培训钱是小事白耽误的事情就不好说了, 毕竟做人还是负责点好. 很显然我当头儿的话, 也容忍不了这个; 但是我更容忍不了手下的程序员不学习. 对我来说, 要么是给他安排些较轻的任务, 留些时间学习; 要么, 等任务完了, 就请他走人好了. 反正社会不缺混日子的, 这样的程序员, 我也不指望就因为他了解项目多些, 就能比别人更适合维护已有项目. 很多管理人员在技术上肯定没法跟我比, 所以我也想请他们注意一下: 无论长期还是短期, 只有超短期的需求, 才应该让你考虑保留一个不学习的程序员; 另外, 别光顾了耍大刀, 不知道留出磨刀的力气和时间. 否则组织一定会为此付出代价; 对于组织上层来说, 这种代价还往往不是显而易见的. 毕竟第一生产力带来的格鲁夫所说的那种十倍速变化, 其威力相当可观. 昨天还运行良好的技术队伍, 很可能今天就不适应竞争了.

关于这一段, 最后要说的是, 对于挣两年前就关门的组织, 和已经想好自己人生就是瞎混加上其它对你更有意义的事的程序员, 不在此列. 我不排斥谁, 现实和快乐所造就的人的选择, 都值得尊重. 仅仅是提醒一下要在IT这条路上走得更远的个人和组织罢了.





没想到又这么长. 下一段又是扯大嘴八卦的, 又是Martin Fowler. 前两天闲着没事, 又翻了翻我经常打击它一下, 又经常引用里面的话的POEAA. 最后一章有一段讲"隐式接口", 具体的记不清楚了, 大概是说什么的也忘了, 不过, 老马丁把Xxxx["yyyy"]这种用法(更广泛的就是有一个通用的方法, 怎么用完全看用户的逻辑)叫做隐式接口. 手头也没有合适的书, 随便翻了一些, 比如Effective C++等等, 发现真是扯淡. 比如Meyers说的隐式接口, 指的是该接口不由显式的签名构成, 而是由有效表达式构成, 并且也在编译器完成完成检查. 其他书或者作者表述也和Meyers相差不大.

如果你忽略"在编译器完成完成检查", 那么很难说清楚Xxxx["yyyy"]是不是一个有效表达式. 这说明Fowler还是从隐式接口抓住了一些东西, 但很显然他搞错了. 可能又要有人说我咬文嚼字了, 不过在我看来, 这是很严重的概念上的错误, 将隐含着某种业务上的接口, 和隐含接口这个纯粹的程序概念, 彻底混淆. 对于我这样的入门程序员, 说错很正常, 作为一个大师, 尤其是建模/面向对象/模式方面的大师, 这个实在说不过去. 虽然我这次翻的是中文版, 但是印象里英文版也用了implicit interface这样的字眼. 没错, 我跟Martin比是一个小菜鸟, 但正是因为如此, 我不得不抱怨一下: 这个问题是我能搞清楚的, 也不太影响做设计, 写代码; 但是在那些更复杂的地带, 到底还有多少陷阱?

我的"老菜鸟"的说法是: 一方面, 他总结了很多我们需要的知识和经验. 一方面, 他就是一个老菜鸟. 说白了, 想想大嘴们成长的道路和当一个合格大嘴要花费的工作量, 就知道, 其实Fowler这样的大忙人, 能用来求甚解的时间并不多. 他怎么可能不菜呢? 不过这并不是说, 我们, 比如我, 就有理由去不尊重他, 或者全盘的否定他的水平. 比如, 哪怕他见过经历过的项目跟其它一些大牛的人比少些小些, 即使不算那些他间接接触的, 也比我要多得多也大得多; 钻研东西即使不像某一专家那么深入, 他所处的环境也让他了解的比我细致的多; 他有再严重的疏忽, 很显然在相关领域的深度和广度也比我强得多. 这个就是"老"字的含义, 绝对是客观的, 那话怎么说来着, 我吃的米还没有他老人家吃的盐多. 并且我个人也引用过Fowler的很多东西, 也在他传道授业的过程中, 拜读了他的著作, 大大的受到他的指引, 我怎么能不尊敬他, 而且甚至感激他呢? 不过, 一个两个问题, 就可以让我们提高一下警惕, 在我们学习知识的时候(其实又是跟学习相关的话题), 不要因为作者是谁, 或者其它这些因素影响我们的判断. 尤其是一些我们还没深入的问题, 不要让先看见的一些东西, 变成了一种成见, 而这成见却往往根本不是来自于我们自己的.

什么时候都要保持怀疑的精神, 正好前两天读一本从博弈论角度看应该如何做人的书, 也强调了这一点.





最后一段想说说面向对象的相关话题.

设计模式本身其实不像有些人说是种思想, 只是它介绍的那些手法体现了一些思想. 对于SICP这样的基础入门书籍(是本大学教材), 这些思想是一上来就强调的. 不过大多数命令式和面向对象语言使用者, 看起来不习惯罢了. 老外有篇文章, 大谈特谈如果用FP编程, 设计模式根本不存在, 因为你的编程方式直接就解决了设计模式所体现的那些思想要解决的问题, 具体手段当然就更不必要了. 他说的完全正确, 可我自己也尝试将编程风格更多的FP化, 最后发现总体来说就我的FP水平, 这么搞纯粹是捣乱; 对我来说, FP将片断拆的更碎, 而且不容易管理. 我个人的看法是: 毕竟FP因为性能等原因错过了编程语言发展的最好时代, 缺少了广大开发者的支持, 所以不会有大量的糖豆式的使用方法上的优化, 在结构化和其它一些方面, 甚至IDE这些, 提供的便利实在太少了. 而对于命令式编程来说, 虽然对象在Anders嘴里不过是个糖豆(而委托在Anders嘴里则是FP的全部, 反正对他来说都没什么了不起啦, 可能象他这样真正的大师眼里一切都是浮云); 但是这样的糖豆越来越多, 再加上很多设计思想和设计模式等具体指导, 也就逐渐的把命令式在设计和实现时的弱点消除很多(在这里讨论的不涉及没有状态等根本性问题和命令式编程的并发等原生问题).

命令式编程, 尤其是面向对象编程以及对接口的重视, 有一点就是增加了很多的繁文缛节, 比如你一个类, 为了和框架配合, 要实现一个IDictionary接口, 我靠, 那一堆没有实现也根本没必要实现的方法啊..., 就是有IDE支持都嫌烦, 如果需要再多实现俩接口, 什么TM的优雅, 根本是P话.说白了就是为了实现类型和约束呗, 越搞越复杂. 幸亏新的糖豆不断出现, 毕竟, 繁文缛节也可以被隐藏起来. 要说的是, 类型系统的复杂程度, FP编程也是照样要面对的. 静态面向对象语言的发展过程, 简直就是解决问题同时制造新问题然后再解决的过程, 但我相信发展下去最终能达到一个比较稳定的状态.

嗯, 上面这些纯属废话, 我的体会是, 既然程序语言是让咱们表达的这么一个工具, 过去那些我顶礼膜拜的各种原则, 最好再掂量掂量. 想要掂量它们, 你就得有更高级一点的原则. 这些个原则(对我来说)归根结底是什么呢?

首先, 你写每一部分功能或过程的时候, 应该根本不(用)想别处(有的时候想也没用), 这样一切就简单的多. 这即是一个最早想要达到的目的, 也是最终会接近的几个目标之一. 在这个过程中, 把其它任务的实现, 当做早就实现好的, 就好比你对.NET Framework或者其它基础框架的使用一样. 比如一个简单又有效的手段是, 在实现A时, 有一个任务B, 凡是涉及任务B的, 那么就建立一个任务B的空壳, 假装B已经实现好了, 并且直接调用B上面的操作. 在这里需要锻炼的是一个快速反应的直觉和判断是否真的有一个任务B的能力. 最后达到的效果是, 建立的那些空壳在A完成后, 不用过多调整. 我的经验是, 那些随手建立的空壳, 或多或少需要调整; 只是再实现A时, 尽量不要关注它们, 尽量让A本身合理即可. 当然, 仅是遵循这个做法, 而没有相应的技巧, 也不可能完美.

其次就是需要具备的能力: 能把共同的过程或那些能规范化的东西不断的提取出来. 面向对象总说封装变化, 其实要我说更关键的是先要封装不变化的: 在尽量固定住不变化的东西的过程中, 自然而然就会将那些不稳定因素, 设定一个约束或者契约, 然后排除出去(即封装变化是由固定不变化所自然导致的). 这时候继承多和多态就有用武之地了,Strategy啦TemplateMethod啦AbstractFactory啦就都出来了.这与封装变化的说法看起来似乎是一码事, 但是角度就完全不一样(如何看待最终没有本质差别, 但可能改变我们掌握它的难易度), 从找寻变化的规律容易, 还是从不变中确定入口容易? 有了这个能力, 可复用之类的口号就可以逐渐变成现实, 也能很敏感的意识到哪些东西应该放到另一个任务里去, 在第一步中所说的做法就可以更好的得到贯彻和实施.

最后是粒度大小要合适, 以解决一个或一类基本问题为基准是一个我觉得比较适当的做法; 当技巧更加熟练的时候, 我们有时可能会选择归并一些东西, 而分解另外一些. 有了这些基本的颗粒, 剩下的就是组装. 对于一个不像.NET Framework那么基本的东西, 颗粒的大小往往不必那么严格, 有时可以感觉怎么顺手, 就怎么来; 另外就是可能根据具体情况, 比如以简化为目的或者为了更好的组装等, 来调整颗粒的大小.如果实在不合适而不能对接, 那接口的设计和那些Adpter啦Bridge啦之类的具体方式方法怎么运用, 也就是自然而然的事了.

其实我说的这3步, 每一步都是以上一步的意识为前提, 下一步是都是为了解决上一步可能会碰到的问题才发展出来. 在实践中只要贯彻, 学习面向对象也好, FP也好(可能FP还要少一些不必要不本质的东西), 都要容易得多. 无论什么方法什么原则, 我个人感觉其目的主要是: 降低我们直接面对的复杂度, 将有迹可循的玩意都放进抽屉, 只剩下从需求而来的工作(因为这些怎么都要做).

其实这里头唯一一个学问就是, 如何找准看进去的那个点, 这个学问就是读万卷书不如行万里路了; 唯一一个技巧就是, 如何象挤牙膏那样, 把不相关的东西给挤出去. 建立模型要围绕需求, 实现则要把需求当垃圾, 从这边到那边的扫来扫去, 最终把它们赶到合适的位置上. 工作量大, 实现的乱糟糟, 往往就是对上面的三板斧把握的还不到位, 这就相当于自己作为自己的用户, 给产生很多隐性的需求的效果, 系统里剩下的垃圾堆应该是那些最接近来自外部的需求.

比如不知道大家怎么看待Page基类和咱们写代码的aspx.cs: 其实它可以被看作一个中介者, 这点[DP]上说的很明白了. 如果从实现一个页面展示的完整过程这一角度看过去, aspx.cs可以说是最脏的地方, 它和页面上每一个控件都有链接, 而不同的控件们仅仅是它连接的一小部分对象, 甚至最终还可能包括了咱们具体的业务需求, 就像GoF说的, 中介最后很可能变成了一个复杂无比的庞然大物. 按我的说法, 如果把WebForm框架也做为实现的整体看过去, 咱们写东西的这个地方就是个垃圾堆: 因为WebForm解决的是咱们这些用户的需求.

反过来咱们设计系统时也可以这样, 面条代码, 超大超复杂类型, 不是不能有, 而是随着可以固定的东西一个一个被固定住, 从各个不同地方挤出很多多余的东西, 然后找一个或几个合适的方式给他们安家. 不过不要把这种方式和较极端的XP等同, 预先设计之类都是很有必要的: 猪肚子下不出狗崽来; 折中和调整, 是适合从普通人到.NET框架作者的万金油. 就我的经验来说, 这样的实践和学习的方式, 要比一上来就想如何去符合面向对象的各类原则, 自然和舒服的多; 当然这种方式也有缺点, 既然指导手册趋于简单化, 那么在积攒了足够的经验之前, 你没法一上来就象一个架构师或设计师那样工作, 可是, 程序员还没当好, 就真那么容易变身成一个设计师吗?

好像又说多了, 开头还说不长篇大论呢, 就此打住. 最后说一句, "吾爱吾师, 但吾更爱真理", 只有我们踏踏实实的去学去问去钻研去挑战去生活, 才是我们对大师哪怕大嘴, 还有在现实中支持我们的那些人, 最好的致敬.

posted on 2007-11-17 22:13  怪怪  阅读(4435)  评论(45编辑  收藏  举报

导航