Daiyi 的个人资料Simple Life照片日志列表更多 ![]() | 帮助 |
|
|
2008/1/24 Jeffrey Ritcher的一堂课花了两天时间,听了Jeff的.NET Threading in C#,受益非浅。
原本参加这个培训是希望见识大师风采,不过学到的东西更是超出自己的预期。回头看看自己以前写的代码,很多地方都值得商榷。
很佩服Jeff在连续讲了4天之后,还能如此热情和耐心地解答大家的问题,给我留下最深刻的记忆,不是技术,而是他这么一段话:
It's poor to write books, which will NOT bring you much money indeed. It requires you staying alone in a room, without talking to anybody, but just typing. Indeed, delivering training like today earns much more money. But I choose to write books, because it could help people, could make impact to the world, I am proud of what I have done, it helps people to write better programs, to make the world better...
希望自己在二十年后,也还能保份赤子之心。 2006/7/13 设计的艺术Plato曾说过,知识是发现已有的东西,而艺术是创造没有的东西。
上帝造就的大千世界,人类发明的新奇事物,都是艺术。但艺术有狭义和广义之分,广义的艺术存在于所有的创造物中,它是一种泛泛的存在形式;而狭义的艺术,也是我们通常所指的“艺术”,存在于美和善之中,它是一种多数派的认同。
认同来自于经验、知识;因此,我们可以说,艺术是人类对“美”的经验和知识认同和肯定的创造性劳动。知识和经验是不断增长的,因此,艺术是无限的。
什么是设计的艺术?我在多年前就问自己。也许今天的我仍难参透设计艺术的真谛,但我却朦胧感觉到了好的设计带给大脑的美感和心灵的震撼。设计的美感在于,在满足需求的同时,做到 close to modify, open to extend。欣赏美容易,创造美难。在过去几个月的工作中,我慢慢地发现了设计的几条重要原则,今天总结出来和大家分享:
1、一致:概念是设计的灵魂,一个好的设计不仅能满足客户的需求,而且要能体现概念的一致。它可以包含很多细节,但在宏观上,它的概念必须紧凑,并且统一。这并不是运用几条Design Pattern就能达到的境界,它的关键在于审慎地分析需求以及实现High Level的抽象。
2、强制:好的设计必须具有强制性,这并不是说将设计实现者的工作机械化。而是为实现者的行为规约,即:实现者必须理解设计、正确履行设计,才能实现目标。这能够将由于个体能力差异造成的风险降至最低,同时良好的系统分层能够减少培训的成本。通常情况下,设计只是定义了系统交互的接口或机制。具体的实现工作将富有挑战性和创造性。
3、适度:好的设计在于适度。设计就像说话,说太少让别人去猜,说太多就变成了唐僧,不仅说的人辛苦,听的人也痛苦。设计不足和过度设计就是两个极端。这个平衡需要经验来掌握,另外,就是利用良好的开发过程(例如Agile)来进行规约。
4、不因“恶”小而为之,不因“善”小而不为:设计往往在一段时间的演化后失去它本来的味道。原本香喷喷的一道菜很可能后来放入了不恰当的佐料而变成“四不像”。很喜欢Martin Flower用Bad smell来形容破坏系统一致性和协调性的代码。要防止设计的变质,我们必须做到不因”恶“小而为之,不因“善”小而不为。即,每次对设计的改动必须被反复的复审:是否破坏了设计的一致性?是否让某部分的设计产生了歧异?
对程序员们的建议
如果你想成为一个设计者,你首先要做到下面一些方面:
1. 词要达意:在设计类、接口和方法名称时,一定要体现设计者的真正意图。我曾经有过花20分钟想一个类名的经历。如果有一天,你偶然发现自己对类的命名和系统库相同时,就说明这点你做到了:)
2. 具有大局观:很多程序员之所以无法超越实现者而成为设计者,往往在于他的眼睛习惯于看细节,对系统的演变缺乏嗅觉。培养大局观,就是要通过分析搞清楚,哪些是必须在设计之初就确定的,哪些是在实现的过程中再考虑的。项目是一个动态的过程,但其核心目标不会变。设计也一样,虽然随着需求进行调整,但却有其持久不变的东西。当这种持久不变的东西和需求冲突时,考虑需求是否在形式上可以改进。
3.开阔的视野和广博的射猎:设计者不能想当然。他必须对设计是否能实现目标有着清楚的认识。这就要求设计者具有开阔的视野和广博的射猎。不要再把问题局限在“如何实现Zip文件的解压”这类细节的问题上,你应该花更多时间去看看技术发展的方向和那些被给予高度评价的开源项目。
设计者的乐趣
相信我,设计者的乐趣要远远大于一个实现者。抛开功利,设计带给人单纯的创造事物的快乐。
苏格拉底两千多年前就指出了最大的幸福是玄想。
设计,这个最接近玄想的工作,也成了我最大的幸福源泉之一。
2006/6/14 冰火两重天 (Posted on 2006/06/08 13:55)职业的乐趣 编程为什么有趣?作为回报,它的从业者期望得到什么样的快乐? 职业的苦恼 然而这个过程并不全都是喜悦。我们只有事先了解一些编程固有的烦恼,这样,当它们真的出现时,才能更加坦然地面对。
[节选自《人月神话》] The Mythical Man-Month (Posted on 2006/06/06 09:15)有时候感觉team处在一个焦油坑中,越是猛烈地挣扎,越是摆脱不了下沉的困境。 以前从来没有意识到影响项目成功的最大要素,直到自己参与到一个较大型的Project中来。在过去的日子里,自己往往能凭着一己之力贯彻从需求分析到项目部署的全部过程。需求,不外乎是对系统理解的内伸和外延罢了。因为那时候,完美主义的我总会尽力将系统设计得尽量flexiable。对于小项目,这是可以接受的,因为稍微复杂的设计并不会给小系统增加多少复杂度。但是对于中等、大规模项目,over design将让大家难以接受,both cost of time and cost of human resource. 在大学的日子里,需求分析在追求技术含量和设计美感的偏执下被贬低得一文不值。大家往往是谈MIS色变,MIS也成为了没有技术含量的代名词。然而,工作后慢慢发现,真正阻碍一个项目走向成功的,并不是对技术把握的不足或是系统设计的缺陷,而是对需求分析的漠视或者需求变化的无常。我们可以很好地管理代码,也可以在技术框架下让程序员服从于设计,但我们不能让客户停止他们跳耀着的思维。毕竟而今眼目下,市场是检验项目成功的唯一标准。 需求像一种无形的手,它驱使着一个个天才的大脑去做一件件无奈的事情。无奈不仅体现在不断重复已有成功的boring,更体现在它的变化无常让人琢磨不透。 需求可以变化,但是作为一个好的PM,更能将它的变化纳入自己的计划,让它可控地变化,让它每一次变化都落入我们的“陷阱”之中。同时,对于过于随意的突发奇想,我们应该理直气壮地说No。一个成功的项目,不仅在于她实现了多少需求,更在于她合理地拒绝需求。 大象无形,大音无声。设计的美感来自于包容,需求的艺术在于接受和改变的平衡。 浅谈代码生成 (Posted on 2006/05/25 16:03)今年年初,我花了大概2个月的时间设计和实现了一个代码生成框架-CGE(the Code Generation Engine)。现在想想这个名字,真不具备任何的意义,本来想改成MetaForge,但是boss觉得大家对CGE这个名字已经耳熟能详了,加之念起来也琅琅上口,于是保住了CGE的名号。 这段时间,随着CRM Team逐渐成熟,我已经能脱离CRM Team而重新回到了“思想者”的位子。虽然还有Verticle Search Engine等需要研究和探索的问题,我却也有了相对充裕的时间来对CGE在过去3个月中对CRM Team开发过程的影响做一些总结。关于代码生成框架的再思考一方面来自于自己的一些新想法,更多的应该是得益于CGE在CRM开发过程中的应用经验。 现在是时候重新改造CGE了,今天将自己对代码生成的理解陈列一番,一是希望总结一下这半年来的经验,二是希望大家能有新的思路和见解。 在开始CGE Project之初,心里是没底的。最高目标深不可测,最低目标倒比较实际和具体。启动CGE的初衷是提供一套需求描述语言,并在需求的基础上实现Java Bean Class的自动生成、Hibernate映射文件(hbm)的自动生成、以及数据库的自动生成。归纳一下,就是至少能实现MVC框架中Model的自动化生成。其实有了hbm,通过Hibernate tools,我们能够方便地得到数据库的DDL。 实现最低目标是比较容易的,因为Java Bean Class的信息已经能被UML完备地描述,我们只需要在UML加一些辅助信息,就能生成hbm。但是,大概花了一周,在做完了第一个实验品并顺利地实现目标之后,我却将之前的设计全盘推翻。原因是,在基于XML的CGE Model Document中,UML主干信息和辅助信息紧密地交织在一起,又由于辅助信息会根据需求的变更快速地膨胀,这使得CGE Model要么难以用Xml Schema来规约,要么难以在将来根据需求扩展。 在反复的思考后,我选择了Meta-meta模型来设计CGE Model,所谓Meta-meta,即双元模型。这其实是我在思考CGE设计时自己想到的词汇,没想到后来在Google上还搜到了这个词,一直相信词汇(或命名)的运用是体现设计者大局观的一个视角,我确实内心窃息了一阵:)。现在先来解释为什么是Meta-meta吧,第一个meta指的是UML结构的元信息,它描述了对象的数据和逻辑组成;第二个meta指的是对UML元素的修饰信息。做一个比喻,前一个meta体像是树干和树枝,而第二个meta却像是叶子和树枝上的悬挂物。前者的形式是固定的,而后者的形式却是变化的。前者可以用DTD或者XSD来规约,而后者却因为不受规约的影响能自由地扩展。后来,经过进一步的思考,我引入了Meta-schema的概念,用来规约第二个meta。这是一个未能完全实现的概念,它描述了什么样的叶子可以用于什么样的主干,并定义了一系列的高级特性,例如meta的命名空间,meta的默认值,meta的继承等等。 我后来将CGE分成了三层:核心层(Core)、方法层(Methodology)和业务层(Business)。 核心层囊括了Model的定义,Meta的规约以及模型元素的查询。它实际上提供了一个在对象的网络里挖掘信息的机制。 方法层是什么?方法层将二维的世界分解成两个一维的世界,二维的世界是由横纵两个侧面来定义的,横是软件项目的规模,通常认为是具有相同处理方法的不同实体的个数,我们记为m;纵是做一类事物的所需要的步骤,通常认为实现某种类型的逻辑所需要的社会平均时间,我们记为n。传统的软件开发过程通常需要m×n的代价才能完成,而CGE的方法层将纵向的方法抽象出来,在核心层建模的基础上,将整个项目的代价变为m+n。在CGE的开发过程中,m为建模所需要的时间,而n则为探索以及泛化一类事物的解决方法的时间,不难理解,方法层所需要提供的输入是文件模板和核心层的模型,输出是对于模型中的每一个对象,采用定义好的方法为其产生输出。 业务层是建立在方法层的上层,它直接面向用户,提供一系列的工具和模板方便用户建立自己的解决方案,它可以是一组自定义元数据(meta)、一组文件模板以及一组外部资源的集合。它直接面向具体类型的项目,为它们提供自动化代码生成的解决方案。 随着最近几年AOP的迅速发展,声明式(Declarative)程序编写方法被大量地应用。它有效地利用了语言反射机制,为我们提供了一套根据接口来请求服务的途径。我将AOP中常见的设计模式IOC(Inversion of Control,也叫Component Injection)引用到代码生成的过程中,而我们只需要加入新的Meta,就能够在代码生成过程中控制类所需实现的接口。例如,在我们CRM项目中用到了crm:enable-search这个meta(它的前缀crm类似xml中的命名控件前缀),这个meta悬挂于类的Member field,它告知我们的业务层,我需要将这个字段加到高级查询的条件列表中去。这样在我们生成类定义的时候,会检查该类的模型中是否有成员变量申明了这个meta,如果有,则让该类实现Searchable接口,并自动生成Searchable接口的getSearchEntries方法对于该类的实现。 CGE虽然已经能为我们做很多事,但仍有很长的一段路要走。虽然在成都的日子已经不多了,但我想,无论是出于工作还是出于兴趣,我都会像照顾自己的孩子一样将这个项目完成,并尽力地将其贡献给开源社区(由于过去的工作是所在公司的一部分,我需要获得boss的许可)。 下图是CGE Project的发展方向,真希望有人能和我一起去实现她……
Any intelligent fool can make things bigger, more complex, and more violent. It takes a touch of genius—and a lot of courage—to move in the opposite direction. If you have built castles in the air, your work need not be lost; that is where they should be. Now put the foundations under them. I have the world’s largest seashell collection. You may have seen it. I keep it spread out on beaches all over the world. iframe的Document属性 (Posted on 2006/04/20 16:24)在DHTML中,我们都应该很熟悉iframe.document属性,而iframe.Document(注意哦,是大写的D)属性却很少被提及。
iframe.document指向的是其所在的文档对象
而iframe.Document指向的是该iframe内部包含文档对象。
差之毫厘,谬以千里。切记切记…… |
|
|