Posted by 鼎鼎 on Jan 15, 2009 in
软件
最近比较闲,一直在向老大讨教整套软件开发的流程,虽然其中的各种概念都在平时的工作中经常提到,但一直没有一个系统的理解。自己一直做的工作虽然其中也有比较完善的设计,但是从总体的角度来看依然属于具体的范畴。在他手下做了一年多,之间的沟通也比较流畅了,当然是建立在比较认同他的思想的前提下。
先普及几个经常提到的概念:
1、概念完整性
2、角色定义:确定软件真正的使用者
3、需求定义:做什么
4、规格定义,也叫功能定义
5、软件是一个有机体,设计的目的是为了让这个有机体可以收放自如,其他的所有都是达到这个目的地手段。做软件和做别的任何事情都一样,要找准角色,站对角度,如果使用者这个角色定位不准,角度没站对,做出来东西八成得不到市场的认可。下面是总结的开发流程:
1、角色设计:这个角色必须是最终用户,它的特征以及使用该软件的习惯非常典型,具有很强的代表性。
2、需求定义:这个阶段是解决做什么的问题。角色设计出来后就要站在这个角色的位置上来定义需求,做什么的问题就会非常明确,这样需求就是由这个角色提出的而不会依赖于某个制定需求的人或者老板拍脑袋的主观产物。这部分是在讨论该为用户做什么的问题。
3、规格定义:也叫功能定义,关注的是怎么做的问题。这部分主要是站在软件设计者的角度来分析要通过什么手段来实现角色的需求。这个阶段最好用手绘来画出界面上需要的功能来和用户沟通或开会讨论,这样比起用专业软件画出界面来沟通的好处是不容易让用户偏离功能本身,而提出一些与功能无关的建议,从而偏离规格定义的意图。
4、总体设计阶段:需求和规格确定好之后进入设计阶段。总体设计首先要确定软件的大致架构,分析是否需要分层,需要分几层。在这个阶段基本上可以确定该项目大致可以分为几个小组来做,也就是常说的横向切割,比方说:该项目可分为UI层、领域层、存储层,那么基本上可以分出三个小组来做。总体架构师需要负责层与层之间的协调,这是通过接口来体现的,层与层之间的接口来保持各层之间的概念完整性,这个时候做总体的人的任务已经完成。如果项目不大那么可能项目的分割就到此为止,如果项目很大,那么下面各小组的负责人要继续分割,这个时候就是纵向分割,大体是根据功能来分。各小组长负责小组内部分部分的协调,通过接口来保持之间概念的完整性。接口定义的重担就落在小组长的肩膀上。当然如果小组长没有足够的经验来把握这个小总体,可能还需要总体的架构师来帮忙。
5、具体设计阶段:任务都分配好了,就进入各位工程师具体设计的阶段。自己的模块也不能乱写,最好要有设计,要想办法封装变化,否则软件倒是写好了满足了现在的需求但是对于变化都非常头疼,这样就是不成功的软件。这个阶段一般要画一下静态类图,好好设计一下。
6、编码阶段:设计做好了就要严格按照自己的类图来实现,有可能在实现的过程中发现设计的不合理要及时修改类图,然后再编码,尽量保持自己代码和设计图的一致性,这是个循环往复的过程,写代码的过程也是验证设计合理性的过程。编码完成的时刻才是设计图完成的时刻,否则可能会经常修改。
在整个设计过程中架构师、小组长、程序员各自维护各自的概念完整性,各司其职,架构师负责层与层之间的概念完整性,小组长负责层内部各模块之间的概念完整性,程序员负责自己模块的各个更小模块或者各类之间的概念完整性。
Posted by 鼎鼎 on Dec 12, 2008 in
软件
今天老大让统计下我们这个项目的代码量,就从网上找了个软件把项目的20多个模块的代码量分别统计了下,不算测试代码总计10万行多点。其中有自己的两万,以前从来没有统计过自己项目的代码量,别人问起的时候自己一点概念都没有。在遇到老大之前对于软件的很多概念基本上为0,没有方向。
仔细想了想,这一年来其实同一个模块前前后后差不多写了三个版本。第一版是标准的SmartUI,第二版本来是想把领域层和ui层分开,但是只是从概念上作了区分,而实际上并没有分开,当然比起第一版代码量减少了很多,对之前完全拼脑力的状况改善了不少,拿给用户虽然用的也不错,但是需求的变更带给我的麻烦还是很多,而且那段时间老大经常给灌输庖丁解牛的概念,让有机会尝试分层设计,我也开始非常正式的关注分层设计和一些设计模式,开始看一些软件设计的经典,大部分都是思想性的为主,当然这和自己的性格有关,如果想让自己心服口服的改变做事方式,必须要对这种方式有强烈的认同感。之后开始试着把前面项目的模型用静态类图画出来,这样可以提供一个和老大沟通的平台,之后就拿着最原始的类图开始了我漫长的半年的设计方式的转变。这是个痛苦的历程,遇到无数次无法“知行合一”(最近在看明朝大哲学家王守仁的历史,所以现学现用)的情况,曾经无数次想过放弃,想用回原来的老路子,无数个晚上在家里自我折磨,其间模型修改过不下20次,代码废过无数,终于看到了曙光,最终完成了我的第三版。庆幸自己的坚持,也感谢老大的不厌其烦。第三版终于按照分层设计的概念分成UI层、领域层和数据存储层,任何一层的修改都不会牵扯到其他层,而且领域层的设计也考虑了未来的需求,结构稳定。第三版完成后突然间有了质的飞跃,这也是我第一个有完整设计的软件。当然我也给了自己一个奖励就是新疆之行。认为有以下几个经验总结:
1、代码写到10000行是个坎儿,这时候会遇到天花板,当然能力超强的人除外,虽然还可以继续写但之后就是要拼体力,这时候就一定要思考是否方法出了问题。否则可能一辈子只能写小软件,或者给你个领导的位子都不知道该怎么当。
2、写oo软件,很多问题只有站在一定高度才能体现出来,所以看问题的角度一定要改变,这样才能学会如何抽象。抽象程度不够,写出来的东西怎么看怎么别扭,当然抽象也要有个度,过犹不及,所以具体问题具体对待。
3、做设计和实现的过程中一定要时刻记住保持概念的完整性。虽然这个词我已经要听烂了但是体会还不是很深,还要继续。
4、在尝试改变方法之前一定要让自己从心里对新方法有认同感,否则痛苦的经历很容易让人放弃。
5、在学习的过程中要分清主次,把握住大方向,不能在细节上钻牛角尖,否则特别容易忘了目标。有时候不要太勤快,懒有懒得好处。
6、写软件之前一定要做设计,至少领域层的设计不能省。
7、实现的代码一定要严格按照设计的类图来做,不能偷懒,图上没有体现的依赖坚决不能依赖,图上看不到的代码里也绝对不能让看到。如果发现有问题一定要返回去考虑设计是否有问题。设计是代码的原型,代码是对设计的检验,这在改变方法初期尤为重要,因为这时候以前的习惯经常会影响你。
8、前期一定要注意知识的积累,虽然看了可能不懂,但也要混个眼熟,知识积累到一定程度才能起作用。
9、不用没信心,不用觉得自卑,你碰到的问题基本上每个人都会碰到,国外的很多大牛都是这样过来的所以他们才研究这些模式和方法。至少我老大说他曾经也是我这水平。关键是要认识到自己的问题所在。
10、这个过程很痛苦,但一定要坚持,放弃了一切都等于白搭。
就这些了,也算是对自己的肯定和鼓励。
Posted by 鼎鼎 on Mar 13, 2008 in
软件
4 思想,无招胜有招
4.1 阶段释义
客户:我们公司有二十个下属单位,每个单位分别有一套自己的销售管理系统。我们想了解各个单位的销售情况,现在是每个星期由下属单位上报周报,周期太长了,不利于领导及时掌握情况。
老李:如果把销售数据自动地集中到总公司这边来呢?
客户:集中?有什么好处?
老李:数据集中后,总公司可以实时掌握销售情况,不用等上一个星期。根据集中后的数据,您只需要打开电脑,就能看到每小时的销售变化情况。
客户:那挺好啊。只是,怎样来集中数据呢?要花多少钱?
老李:可以在每个下属单位分别安装一套程序,实时地把进销存系统中的数据提取出来,然后上报给总公司。在总公司这边,也安装一套程序,用来接收下属单位送上来的数据。这样,数据就全部集中到总公司了。从现在的规模来看,您只需要在总公司增加一台服务器,用于接收数据。当然,总公司与下属单位的计算机要能通过网络互联。请问现在已经联网了吗?
客户:我们现在已经联网了。公司申请了专线,可以进行视频会议。
老李:噢,那就花不了多少钱了。您只需购买一台服务器,再加上软件的费用就行了。
客户:噢,听上去挺好的,那你们公司能不能做这件事……
(注:上述对话,纯属虚构。目的是为了说明不同阶段所做的事。实际项目中,您可别建议客户“实时提取并上报销售数据”,所花的钱,也不只是一台服务器那么简单,^_^)
老李是公司的研发副总。他经常拜访客户,了解客户有什么困难和需求。本例中,客户觉得每周上报一次,时效性太差——这就是需求,同时也是老李的机会。老李运用手中所掌握的技术,帮助客户策划出一个分布式采集数据的方案。老李只需要知道:(1)现在有许多种成熟的分布式技术,能实现分布式采集;(2)老张对这些具体的技术很熟悉。至于如何去实现分布式,就不是老李要考虑的了。
老李属于第三阶段中人:既了解技术,又了解业务。从技术出身的背景,使得老李在与客户交流时更务实。许多人对业务非常熟悉,但由于不懂技术,不知道什么事能做,什么事不能做,与客户的交流经常流于形式,只能开花,不能结果。既懂技术又懂业务的复合型人才,往往具备独特的优势,使得他们能在事业上达到别人无法企及的高度。
第三阶段的人,看问题的角度已不再局限于技术,而是更一般化、通用化。其实做信息系统也好,做通用软件也好,思维都有一些模式可循。例如,在决定开发一个产品前,通常需要问自己几个问题:
n 目标客户是谁?
n 客户有什么烦恼?他在抱怨什么?
n 客户现在已经有了什么?还缺什么?
n 你能给他提供什么?
(注:后来我才知道,这些问题早已出现在RUP的Inception阶段中,Inception要解决的是商业风险,上面列的几个问题,就是Inception阶段的成果——Vision Document)
这些问题弄清楚后,基本上,“给客户提供什么东西”就已经定下来了。然后就可以与架构师一起,讨论这个产品,并最终由开发小组去实现。与第二阶段中“我知道它能-I know it can work”不同,本阶段主要特点是“我知道它是什么——I know what it is”。
也许你会说:“上面的几个问题,谁都能问,干嘛非要第三阶段中人呢?”没错,这几个问题,谁都能提出来,甚至可以用Word写个模板。但是,提问题容易,回答问题难。同样的环境,同样的客户,不同的人收集到的信息是不一样的。不信?找两个人一起去为某个会议做纪录,然后看他们写的《会议纪录》文档,就知道差距了。许多人不愿意做会议纪录,认为这是低级活,其实不然。会议纪录做得好的人,与客户交流时,就能有重点而又比较全面地记录下有用的信息,甚至能领会“弦外之音”。能达到第三阶段的人,通常都是信息挖掘的高手。
到达这个境界后,不再需要知道什么设计模式,也不需要知道什么是EJB、CORBA(虽然他们都懂技术,造诣也都不低),就象独孤剑圣,已达“不滞于物,草木竹石,皆可为兵”。说起来神乎其神,其实归纳起来,也就两点:
一是识势:俗话说,识时务者为俊杰。用现在的话说,叫“形势比人强”。以一已之力对抗大形势,那是必败无疑。“俊杰”的出现,能推动形势的发展,但也只是“推动”而已,形势是不可能“阻挡”和“违逆”的。大禹治水,疏并导之,鲧不懂这个道理,纵有息壤相助,亦无法堙填。张勋不知道封建君主制已不适合中国国情,而搞什么复辟,唉,可怜啦。具体到软件项目,如果客户想搞分布式,你却建议他搞大集中;客户想要三层结构,你却建议他用二层C/S,岂不谬哉?所以说,识势是应具备的首要能力,是重中之重。
二是知人:光说不练假把式。如果仅仅是识势,而没有得力的人相助,那也是一场空。刘备身具“帝王之后,汉室宗亲”的血统,打着光复汉室的旗号,甚得人心,可谓是识势(至于刘备是不是真的想光复汉室,鬼才知道),但在遇上关、张前,他只能卖草鞋,在认识诸葛亮之前,也一直被赶着屁股跑。再说老李,如果没有老张,任他舌绽莲花,天上也不会掉下一套分布式系统来。
4.2 应该做的事
与客户保持经常性的沟通。销售和市场人员,他们可能想不到一些事,与客户的经常性沟通,能让你掌握第一手的资料,从而有助于产品的创意。最好是把客户的MSN、QQ等经常上线的聊天工具的号码弄明白。从MSN的昵称、说明档等很能看出一个人的心情,这里面能表达很多信息。频繁的、不刻意而为之的沟通,容易拉近与客户的距离,让客户把你当成朋友。当然,许多客户,尤其是客户中的领导,通常是不上MSN的。对于这些人,就要谨慎一些了,他们可能不希望被打扰,所以别随便打电话。建议请教专业人士:公司的销售——他们有的是办法。
增加阅读量,扩大信息来源。大量的信息,可以让你了解行业动态,增加你的灵感和创意。上文说过,要锻炼“收集有用信息”的能力。现在都是海量信息,如果不能敏锐地发现对自己有用的信息,那你唯一能做的事,就是在信息的海洋里游泳健身。一个秘诀:看到有用的文章后,随手就保存到本地硬盘里。然后在机器上装一个Google Desktop,让Google帮你搜索。另一个建议就是:最好有属于自己的笔记本电脑。钱不多的,买个活动硬盘也行。
培养情商,增加个人魅力。通常,能对你有用的人,都是些“牛”人,至少是比较牛的人。这样的人是否愿意为你所用,不一定取决于薪水,而更多地在于你的领导艺术——至少要让他们认为,跟着你混是有前途的。《古惑仔》中有一段对白:“我们做古惑仔的,跟对老大很重要”。其实在职场混,跟在江湖混,没多大区别。越往上走,就越古惑。通常是职位越高,圈子越窄,抬头低头,总是那么几个人。到达这个份上,就应了一个平时常说的名词:“人品问题”。人品好而又有能力的人,才能成就大事。
参加俱乐部或沙龙活动。有的信息,尤其是内部信息,从外界是无从得知的。尤其是,许多灵感,可能来自于几个有共同爱好的朋友的闲聊。
4.3 不应该做的事
作为第三阶段中人,通常是一个不小的领导,不应该做的事有很多。市面上有大量的书而供参考。本文只给出从技术出身的领导最常犯的两个错误:
不信任下属。技术出身的领导,往往对那些技术上不如他的人持有一定的怀疑,尤其是当他/她们犯了错误时。用人不疑,疑人不用。你的下属之所以会犯错误,正是因为他/她想真正把事做好。此时,宽容大度加上适当的指导,通常是最好的选择。
自己很有成就感。这是另一个常犯的错误。要知道你是领导,你不需要与下属争抢功劳,应尽量把获得成就感的机会留给下属。如果你事事争先,由于本身的能力与素质,你比下属更容易把一件事做好,但因此而带来的副作用,远大于这件事情本身:下属会觉得没有成就感,没有自信心,渐而渐之,就会影响士气。如果这样,就算你这个当领导的再能干,也不可能把所有事情都做完。
4.4 局限性
俗话说:江湖越来越老,胆子越来越小。当你逐渐成为某个行业内的知名人士之后,得到的东西越来越多,相反,患得患失的心理也越来越重。所谓“壁立千仞,无欲则刚”,欲望太多,就会使自己变得虚弱。
在职场上,你已经是老兵,酸甜苦辣都经历过一些,可谓是水火不侵了。但在人生道路上,起落浮沉,也许才刚刚开始。此时的你,大概已过而立之年,家事琐事有一大堆,人际关系也渐趋复杂。此时能影响你成功的,通常都是些与职场无关的事——恰恰又因为你在职场上投入了太多的时间,职场外的事,多半是一团糟。
4.5 进阶指南
职场内的事,已无须我再说什么了。到了你这个境界后,我只有一句话可说,那就是:人生并不只有职场,正如职场并不只是技术一样。知道独孤剑圣怎么死的不?他是寂寞死的。
4.6 阶段小结
适用人群:工作六年以上(经常跳槽的不算),上限不封顶
输 入:客户需求
输 出:可行的创意或产品定义
阶段目标:我知道它是什么——I know what it is
技术特点:注重思想,不关注技术实现
胜任职位:部门经理、研发副总、CTO、解决方案专家、业务专家、产品经理、高级产品经理等
升级秘笈:换位思维,跳出职场看问题
参考薪水:¥15000以上(仅供参考)
5 附录:关于“三阶段说”
古圣今贤给予我们许多的启示。虽然他们没学过计算机,没当过程序员,但对于人生,对于“道”的领悟,远比我们这些白骨精(白领骨干精英)强。人的进步过程,其实是一个“肯定,然后否定”的过程,这个过程,其实不只三个境界。但是境界三转后,就与“程序员”这三个字无关了,所以本文中不加以论述。
无论是哪个阶段,都需要先“入迷”,然后“解脱”:
n 在第一阶段,需要先在编程语言细节上入迷,然后从语言细节中解脱出来,达到语言无关,从而进入设计这个层次
n 在第二阶段,需要先在设计方法上入迷,然后再从方法中解脱出来,达到技术无关,从而进入思想层次
n 在思想层面,需要先在解决问题的总体思想上入迷,然后又从思想中解脱出来,达到与职场无关,从而进入另一个境界。
以下附两段笔者收录的与“三阶段说”有关的名句,供参考。
n 孙过庭《书谱》:“初学分布,但求平正;既能平正,务追险绝;既能险绝,复归平正。初谓未及,中则过之,后乃通会。通会之际,人书俱老”
n 王国维《人间词话》:“古今之成大事业、大学问者,必经过三种之境界。‘昨夜西风凋碧树,独上高楼,望尽天涯路’,此第一境也。‘衣带渐宽终不悔,为伊消得人憔悴’,此第二境也。‘众里寻他千百度,蓦然回首,那人却在,灯火阑珊处’,此第三境也。”
还有很多,不一一列出了。以君之智慧,必已有所悟。
(全文完,谢谢阅读)
Posted by 鼎鼎 on Mar 13, 2008 in
软件
3 设计,方法为指导
3.1 阶段释义
老李:老张,你负责的这个模块,要有分布式事务处理能力,还要能与客户的OA系统通信,从OA中获取客户资料的数据。
老张:好的。我将用EJB来实现分布式事务处理,然后开发一个专门的接口,用来与OA通信。
老张毕业五年,是项目组的开发经理,负责完成子系统的设计,并指导其他成员完成编码。老张从老李处获得关于所开发的产品的需求情况,然后进行设计和分析,用UML建出模型,并生成框架代码,由小王等去实现。
老张属于第二阶段中人,通常工作了三年以上。此阶段中人,已经完成了一定程度的技术积累。对《设计模式》、《J2EE核心模式》、《UML》等烂熟于胸,张口就是IOC(控制反转),有事没事也要说说AOP,最差也得是Factory、Delegate吧,你要是说不知道什么是Facade,都不好意思跟人打招呼……
与第一阶段“我能——I can do it”不同,本阶段的人,特点是“我知道它能——I know It can do”,对,就是“知道它能”,至于如何去“能”,就不需要关心了。例如老张,他只需要把EJB接口定义清楚,知道有了这个接口就能完成相应的功能,至于小王如何去实现这个接口,是写了三个类还是五个类,就不关心了。
从技术角度,追求的不再是纯粹的技巧,而是方法这个层次,努力寻求正确的做事方法。即关心“怎样才能盖出好房子”,而不是“如何把石头从货车里搬运到工地上”。用流行的话说,就是“只要方法正确,结果就会正确”。
当然,达到这个阶段的人,技巧本身,通常也是很厉害的。举个例子吧,小王要用一个开源的XML文件比较工具,并编了个测试程序,比较a.xml和b.xml的区别,却怎么着都得不到正确的结果。后来老张来了,牛人根本不看JavaDoc,而是拿着XOP提供的命令行比较了a.xml和b.xml,发现结果是正确的,然后直接打开与命令行对应的main(),检查与options对应的API,发现小王少调用了一个API,加上这个API后测试程序就通过了。在这件事中,老张根本不熟悉XOP的API,但他掌握了查找API的方法,那就是:组件或工具,都有其外在特性,通过组件或工具提供的命令行能做到的事,也一定能通过它提供的API来完成。如果不知道如何去调用API,对于开源软件,看它的source code或samples中的main()即可;对于非开源软件,看StackTrace;如果都看不出来,就放弃该软件,选择别家的吧。
此阶段中人,也需要编写程序,但编写的是与业务和框架相关的核心类。所用的语句通常朴实无华,用最简单的语句完成最复杂的功能是他们的习惯。例如,求b和c中的较大值,通常不会写成
result=(b>c)?b:c
而是写成
if (b>c)
result=b;
else
result=c;
因为后者更容易懂,而前者,相对生僻一些。开发经理的工作,是把产品的需求,转变为编码人员能理解的接口或类,并保证团队的所有成员在理解上的一致性、无二义性,在这个前题下,简单而又精确的语句是必然的首选。所以,如果你的经理编写的程序,在你看来很“幼稚可笑”时,千万不要洋洋得意。
舍小巧而用大巧,舍弃繁花似锦的编程细节,换取简单稳定的框架结构,换取无二义性的交流效果……独孤剑圣四十岁前,以玄铁重剑纵横天下,剑法古拙,大巧不工,就是此境界(孤独大侠也走过弯路,30岁时用紫薇软剑,可能是追求剑招的繁复和剑法的华丽,失去控制,最终误伤义士)
3.2 应该做的事
该阶段的人,该做可做的事非常多。须知一个完整的软件产品的开发过程,编码仅仅是其中的一个环节而已。作为开发经理,老张的典型工作如下:
首先充分理解需求,挑选其中20%左右的功能,结合非功能性需求,设计出系统的结构(Architecture Design)。通过边界类、控制类、实体类的应用,分析清楚Use Case中的交互流程,然后用一系列接口来表达这个流程,最后运行各种设计模式或技巧,实现这些接口,建出UML模型,并生成代码框架。
除了开发经理外,你还有可能是项目经理,在中国公司,项目经理和开发经理可能都是你。学习先进的开发方法是你的必修课,什么用例驱动开发、测试驱动开发,不管用不用,你都得知道个大概;选择正确的开发模型也很重要,何时选用瀑布模型,何时选用迭代模型,一定不能含糊。
遵守公司的开发流程,为SQA(Software Quality Assurance)提供必需的文档和数据也是你的本职工作。如果你所在的公司尚无规范的开发流程,那么,你要帮助公司来建立。完整的开发流程贯穿整个产品生命周期,你有可能只与其中几个阶段有关。但只要与你有关,那就要尽力去配合。
该阶段的人,通常在公司中是中层干部,执行能力是一个最主要的考核指标。你的领导,可能根本不懂编程,而项目组里的小伙子们,可能无法领会领导的意图,这时,你就是中间人,好比足球场上的中场,你的沟通能力和执行能力,将决定产品开发阶段的成败。
3.3 不应该做的事
1、尽量少编程。除了“核心接口、类和算法”,不要与其它代码纠缠,那会使你忽视宏观上的问题。而且,你也不一定比小伙子们编得快。只有当小伙子们遇上困难时,你才去协助他们解决问题。
2、不轻言放弃。该阶段的人,工作压力巨大,即使他看上去什么事也没干,他承受的压力也不是编码人员所能体会的。在压力面前,容易失去理智,如果不注意控制自己的情绪,可能会发生一些不愉快的事。
现在的你,可以说是“到哪都能找到工作”了。当与公司、同事发生一些摩擦时,可能会“一怒而去”,这是最要不得的。因为你现在追求的,已不是“能找到工作”了,而是“能找到体现自己价值的工作”,千里马尚且需要伯乐来发现,换家公司就一定能受重用了?而且,不管你是否意识到,你已经学习了许多行业相关的知识,这些知识,在更换公司后,未必能用上,到新公司后,还得从头学习——人生有几次重来的机会?
3、戒骄戒躁。你现在已经是“有本事”的人了,加上工作压力,难免有点脾气。但是切记,你还没有功行圆满,还要“多长本事,少长脾气”。因为你的局限性,与你的优点一样明显。技术等级的提升,应该是让你眼界更开阔,并看到了更大的差距,而不是固步自封。
4、不要迷信新技术。新技术的采用是有一定的风险的。因为技术本身,可能还不成熟。追捧新的框架可能是你的爱好。没关系,作为爱好,是可以的,但不一定要把爱好带到工作中来。老板关心的是你开发出来的东西能否买个好价钱,不是看你用了多少新的Framework。你的用户关心的,是产品的易用性、稳定性,用起来是否顺手,用户同样不会关心你用了Tomcat还是Jetty,甚至连J2EE和.Net都不关心——如果他不需要为此购买新的硬件或者重新培训操作员。
5、多看人文方面的书和文章。此时的你,在技术方面已经有一定的造诣了。但是不是就大功告成了呢?回答当然是“不”,你还需要补充人文方面的知识,即进行感性思维训练。为什么?往下看。
3.4 局限性
你的局限性,与优点一样明显。如果让你列举自己的优点,你可能会说:
n 我精通设计模式,能做出重用性很好的软件
n 我对软件工程很有经验,能做一个好的项目经理
n 我熟悉建模工具、开发环境等,能提高开发效率
n ……
是的,这些都是了不起的能力,但是:
1、 你们公司不是研究所,不卖设计模式,也不是咨询公司,不卖软件工程经验,更不是培训机构,不对外提供“建模工具、开发环境”培训
2、 你知道软件是如何被开发出来的,但很少考虑是否应该开发这个产品;
3、 你不知道用户会怎样使用你开发的产品,你不知道用户喜欢什么、抱怨什么;
4、 你不知道这个产品为公司赢得了多少利润;
5、 ……
一句话,你懂技术,但客户要的,并不是技术。摩托罗拉有世界上最好的射频工程师,但为什么手机就是卖不过诺基亚呢?因为诺基亚喜欢听客户的意见,而摩托罗拉喜欢听工程师的意见。
你说:“我热爱技术,喜欢钻研技术,至于客户在想啥,那不是我要考虑的问题——我甚至不知道客户是谁”。是的,达到你今天的这个境界非常不容易,许多人工作十年也未必能象你这样优秀,你是公司的骨干,是同事的偶像,但是……但是……《武状元苏乞儿》中有一段经典对白:
洪日庆:先别走!行行出状元!如果我没看错,你会是乞丐中的霸主!
苏 灿:乞丐中的霸主?!那是什么?
洪日庆:嗯……还是乞丐!
没错,乞丐中的霸主也是乞丐。你再优秀,也只是公司的中层干部,是干活的人中的霸主——还是个干活的:
n 客户给老板发工资
n 老板给你发工资
n 你不认识客户,客户同样也不认识你
n 既然你不认识客户,那就不知道客户喜欢什么、讨厌什么
n 如果有一天,你的产品让客户不满意(这个概率还是很大的)
n 客户很生气,后果很严重
n 老板请你喝咖啡,并建议你去度假,顺便提醒你从外面把门关好
再来看看圈子里:
n 没有技术,但手里有一堆客户的公司,比比皆是,他们活得很滋润。
n 没有客户,但手里有一堆技术牛人的公司,很少见——都倒闭了。
现在,你知道局限性在哪里了吧?
“正因为你技术太强了,所以只能当乞丐中的霸主,技术恰好就是你的枷锁”
说件真实的事吧。
某天,我奉命与一个合作伙伴交流我们的平台产品,目的是让对方了解我们的平台并在平台上做二次开发。交流进行得很顺利,对方也跟我们签合同了。后来,市场人员去合作伙伴处了解反馈意见,对方说:“你们那个xxxx太厉害了,问什么都难不倒”。回来后,领导就不允许我参加交流了。原因是:“你可能泄密了”。
作为技术人员,我希望充分介绍自己产品的优势,并能应付合作伙伴提出来的各种应用场景和问题。但是,从领导的角度来看,“如何满足应用场景、如何解决问题”本身,就是商业机密,是不能乱说的。举这个例子的目的,就是说明技术人员看问题的局限性。
想要达到更高的层次,就要跳出技术看问题,多了解市场,了解客户。假设孤独剑圣陶醉于玄铁重剑的威力,天天带着到处乱跑,那么他就不是剑圣,而是搬运工了。搬运工最多只能当个中层经理,当不了高层领导。
如果想进入领导班子,与老板一起玩游戏,那就赶快升级吧。
3.5 进阶指南
1、 跳出技术看技术
达到这个阶段的人,在技术上已经“很深入”,眼中所见,尽是技术。但你们公司不是卖技术的,你们卖的是产品,是服务。所以,把你的目光从技术中解脱出来,去思考一下产品和市场层面的问题。例如:
n 市场上有同类竞争的产品吗?
n 当前已有的产品,客户有什么不满意的?
n 我做的产品应该具有什么样的特色?有什么卖点?
所谓“一招鲜,吃遍天”。只要你知道客户想要啥,并能有针对性地开发产品,客户一定会情不自禁地给你钱。客户都给你钱了,老板还好意思不给你个CTO的头衔玩玩?
2、 了解业务
计算机技术必须为具体的行业服务,每个行业都有自己的特定背景和业务知识。技术人员应抓住机会,了解这些知识。我曾在某个电信软件公司任职三年,号称是项目经理,开发电信网管产品。那时我整天的工作就是研究各种框架,讨论各种设计模式,我眼中所见心中所想,尽是WEB、Struts、HTML等一大堆计算机名词。如果你问我“为什么这玩意是个网管软件,而不是淘宝易趣阿里巴巴?”我一定回答不出来。
一个公司里面,真正值钱的东西,不是技术,而是业务知识,技术是实现业务的一种手段,是为业务服务的,主从关系,不可搞错。
3、 加强非技术性的功夫
学书法时,老师曾说过“三分书内功夫,七分书外功夫”。这句话我一直不理解(事实上,到今天依然不理解),但把这句话用于计算机技术,却是明白的。三分书内功夫,是计算机技术,七分书外功夫,就是非技术性的产品和市场了。
可以通过看些“不务正业”的书,来提高自己的感性思维能力,可以多看看市面上流行的《比尔盖茨传奇》《数字化生活》《把信寄给加西亚》等,象《谁动了我的奶酪》这种只会抱怨不会解决问题的书,就不用看了。
3.6 阶段小结
适用人群:工作三年以上,上限不封顶
输 入:软件需求(请注意用词的区别:软件需求,而不是客户需求,你所得到到软件需求,是由别人收集来的,并不一定能代表客户,如果“别人”的水平一般,错误理解了客户的意图,那么你就等着跟他一块倒霉吧)
输 出:设计好的类、接口和算法
阶段目标:我知道它能——I know it can work
技术特点:注重方法,不关注编程语言细节
胜任职位:高级软件工程师、开发经理、系统架构师等
升级秘笈:换位思维,跳出技术看问题
参考薪水:¥6000以上,¥15000以下(仅供参考)
Posted by 鼎鼎 on Mar 13, 2008 in
软件
(本文共分三部分,现在打开的是《第一部分》,欢迎继续阅读《第二部分》和《第三部分》)
1 引子
都说海阔凭鱼跃,又有多少鱼能跃出大海?都说天高任鸟飞,但真正能一飞冲天的,也不过是寥寥数鹰而已;在IT圈里流浪的程序员,当青春逝去、渐至而立之年时,又有多少人黯然退出?30岁,似乎宣告了程序人生的终结。
从学会写第一个Basic程序起,已过去了15年,我也曾为30岁烦恼过。近日《神雕》热播,杨过在独孤剑圣的剑冢中发现宝剑若干,见证了独孤剑圣在人生不同阶段对剑道的领悟。忽有所感,联想起古圣今贤的论述,结合自已这些年来的经历,不禁豁然开朗。
程序之道,在于悟,悟透表象后面的真相。程序人生,大致可分为三个阶段:
n 编码阶段:凌厉刚猛,无坚不摧,弱冠前以之与河朔群雄争锋
n 设计阶段:重剑无锋,大巧不工,四十岁前恃之横行天下
n 思想阶段:四十岁后,不滞于物,草木竹石均可为剑。自此精修,渐进于无剑胜有剑之境
本文针对普通程序员的实际情况,对这三个阶段进行解说,并给出了“升级”的秘笈。所述观点,不适合IT狂人和天才——因为我不是。
2 编码,技巧作先锋
2.1 阶段释义
老张:小王,昨天讨论的那个EJB接口,已经实现了吗?
小王:我已经实现了,现在客户端可以通过EJB与服务器进行通信了。
上述对话,取自于某项目组的会议纪录,老张是这个小组的开发经理。小王毕业一年,在项目组中主要从事代码编写工作。每天上班,老张会给小王分配当天的工作,告诉小王有哪些Java接口,需要写多少个Java类,具体有什么要求等等。小王按照要求,写完这些类后,交给老张,一天的工作就完成了。衡量小王的能力的标准是,看他是不是能做好具体的事,即“我能做(I can do it)”。
小王是典型的第一阶段中人。该阶段中人,通常是入门三年内的,初窥门径,斗志昂扬。在网上常看到的“VB好还是DELPHI好”“.Net好还是J2EE好”等贴子,多数都是由这个阶段的人提出,人气值剧旺(这是合理的,符合人才的金字塔结构),往往争吵得头破血流也不罢休。笔者也曾因此与同班一MM大吵出口,如今回想,深感当年之可爱。独孤剑圣弱冠前,手持无名利剑,凌厉刚猛,与河朔群雄争锋。程序员也一样,手持“编程语言”利剑,以“面向对象”为招式,东征西战,编出代码无数。
2.2 应该做的事
找一家有正经事干的公司,打一枪换个地方的不要。这是重中之重。“蓬生麻中,不扶自直,白沙在涅,与之俱黑”,现阶段的程序员,是无力改变现状的。如果你所在的团队不能按正规方式进行较大型软件产品的开发,那你所能学到的东西就会少许多。如果是正规开发团队,而且有前辈愿意尽心尽力地教你,那就是捡到宝了,不给钱都行。
从技术角度,这个阶段的人,关注细节是必修课,追求的是技巧这个层次。“如何才能用最少的语句实现表达式求值”“i++与++i有何区别”等是最关心的问题。当技巧的积累达到一定程度时,应付日常工作将比较轻松,此时信心爆棚,最喜欢的口头禅是“天底下没有编不出来的程序”,技术特点是对某种编程语言(如Java、C#)非常熟悉,甚至达到“回字有四种写法”的境界。凡事必追根究底,有股子“语不惊人死不休”的蛮劲。
笔者没有任何贬义,相反,是褒义,因为这是必须经历的。佛云:“既未入迷,何言解脱?”如果你是工作三年内的同行,那么应以“入迷”为荣。上学时,老师常教导我们“先把书读厚,再把书读薄”,只有“深入”,才能“浅出”,也是这个道理。
2.3 不应该做的事
年少气盛,固然可爱,但若因此而鼻孔朝天,则是大大的不妥了。你的许多同事,API没有你熟悉,编程也没有你快,但他们能为企业创造的价值却可能比你大(为什么?看下文)。时下流行“态度决定一切”,此时的你,应以低姿态为主,傲气会让你短视。
“技术代表一切”可能是你的信仰。但你的老板可能对技术根本不感兴趣,老板关心的是你能为公司创造多大的价值。许多黑客甚至养不活自己,因为单纯的自我陶醉式的攻击、骚扰、破坏并不能创造价值,通常都是在改行后(例如当安全顾问),他们的技术才能用于创造价值,才能使自己过上好日子。许多黑客则干脆是双重身份,平时从事着另一份职业。所以,如果想挣更多的钱,那你就不能迷信技术(屠龙之技有何用?),而是要审视你所做出的贡献。许多牛人觉得自己水平很高,为什么老板就是不给加薪?反思一下,自己给公司挣了多少钱吧。
2.4 局限性
1、锋芒有余,韧劲不足。该阶段的人,锐气太盛,遇到挫折后容易气馁,轻言成败往往是他们的缺点。(什么?没有锐气?是谁,是谁把你招进公司来的?)
人不可有傲气,但不可无傲骨,傲骨体现在面对困难上。要勇于用抽茧剥丝的精神,去磨,去啃,相信吧,只要你的困难不是想发明质能方程,最终一定会被你搞定的。事实上,你遇上的问题,大多数都可以通过Google、百度搜出答案来。
2、与具体的语言或编程工具绑定得比较紧,受语言的限制较大。
3、需要良好的体力。人到中年,体力上往往拼不过刚毕业的学生,这就是所谓的“程序员30岁问题”的原因。我有一些朋友,已过而立之年,却还在苦苦寻找编码的职位。虽然我很同情,但爱莫能助,如果这种情况继续下去,“寻寻觅觅,冷冷清清,凄凄惨惨戚戚”将是必然的结果。
朋友,赶快升级吧。
2.5 进阶指南
1、多记多写。好记性不如烂笔头,把各种想法写下来,把经典的代码摘录下来(最好用源码工具来管理,推荐VSS),有价值的东西,还可以发表在博客中(俺们那个时候苦啊,网络不发达,呕心沥血之佳作,却只能孤芳自赏),这些就是你的财富,在关键时刻拿来就能用;
2、别忘了挖井。不知是否听说过两个和尚的故事,原文不在此粘贴了,大意是一个和尚天天挑水,另一个除了挑水外,还在寺庙附近挖井。若干天后,第一个和尚还在挑水,第二个和尚已经挖好井,不用再挑水了。编码好比挑水,作为本职工作,自然是要卖力地挑,好争胜的,不妨跟人比比谁挑得多。但在业余时间,可以多看看《软件工程》、《设计模式》、《人月神话》、《极限编程》、《UML》……
3、由外而内,勤修内功。什么编程啦,什么算法啦,统统都是外功。外功练好了,内功也能跟着长进。内功是什么?很多。现阶段最需要的是:灵活的头脑、关注细节的态度以及与人为善的处世技巧。
灵活的头脑,使你能快速学习新东西,这是最基本的。
关注细节的态度让你能“象福特一样捡起地上的纸片”(如果不知道福特的故事,上Google搜去吧),工程实施现场出现的问题,多数都是由于编码人员的疏忽;经典错误“空指针”和“数组越界”,你检查了吗?几十年了,“缓冲区溢出”仍然是黑客的最爱。
与人为善的处世技巧,使你有良好的人缘,前辈愿意帮助你,晚辈愿意投靠你,领导愿意提拔你,哇,好处多多,实惠多多……能否进阶,就靠这了。
(常云:先做人,后做事。无论是程序员还是艺术家,这个道理都是普遍适用的,贯穿人生的各个阶段——而这恰恰又是刚参加工作、涉世未深的新人们容易忽略的。所以在此提出,下文就不再赘述了。)
2.6 阶段小结
适用人群:工作三年内
输 入:设计好的类、接口和算法
职 责:按要求编写类和接口的具体实现代码
输 出:具体的代码
阶段目标:我能——I can do it
技术特点:注重技巧,对具体的编程语言非常熟悉
胜任职位:软件工程师、开发工程师
升级秘笈:多学习软件工程、设计模式等与具体编程语言无关的知识
参考薪水:¥6000以下(仅供参考)
Posted by 鼎鼎 on Nov 22, 2007 in
软件
老早就看设计模式,但基本上只停留在看的阶段,因为对C++中的面向对象理解不深,所以设计模式更是天书,最近的项目是个典型的Composite模式,所以在网上拼命找关于这方面的比较浅显的例子,众多文章中自觉作者把设计模式描述的相对简单,对初涉设计的TX比较容易理解。
另:推荐:http://www.dvpx.com/index_article_display.aspx?Fid=39&id=30
以下转自:http://www.cppblog.com/converse
作用:
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
UML结构图:
抽象基类:
1)Component:为组合中的对象声明接口,声明了类共有接口的缺省行为(如这里的Add,Remove,GetChild函数),声明一个接口函数可以访问Component的子组件.
接口函数:
1)Component::Operatation:定义了各个组件共有的行为接口,由各个组件的具体实现.
2)Component::Add添加一个子组件
3)Component::Remove::删除一个子组件.
4)Component::GetChild:获得子组件的指针.
解析:
Component模式是为解决组件之间的递归组合提供了解决的办法,它主要分为两个派生类,其中的Leaf是叶子结点,也就是不含有子组件的结点,而Composite是含有子组件的类.举一个例子来说明这个模式,在UI的设计中,最基本的控件是诸如Button,Edit这样的控件,相当于是这里的Leaf组件,而比较复杂的控件比如List则可也看做是由这些基本的组件组合起来的控件,相当于这里的Composite,它们之间有一些行为含义是相同的,比如在控件上作一个点击,移动操作等等的,这些都可以定义为抽象基类中的接口虚函数,由各个派生类去实现之,这些都会有的行为就是这里的Operation函数,而添加,删除等进行组件组合的操作只有非叶子结点才可能有,所以虚拟基类中只是提供接口而且默认的实现是什么都不做.
实现:
1)Composite.h
/**//****************************************************/
created: 2006/07/20
filename: Composite.h
author: 李创
http://www.cppblog.com/converse/
purpose: Composite模式的演示代码
********************************************************/
#ifndef COMPOSITE_H
#define COMPOSITE_H
#include
// 组合中的抽象基类
class Component
{
public:
Component(){}
virtual ~Component(){}
// 纯虚函数,只提供接口,没有默认的实现
virtual void Operation() = 0;
// 虚函数,提供接口,有默认的实现就是什么都不做
virtual void Add(Component* pChild);
virtual void Remove(Component* pChild);
virtual Component* GetChild(int nIndex);
};
// 派生自Component,是其中的叶子组件的基类
class Leaf
: public Component
{
public:
Leaf(){}
virtual ~Leaf(){}
virtual void Operation();
};
// 派生自Component,是其中的含有子件的组件的基类
class Composite
: public Component
{
public:
Composite(){}
virtual ~Composite();
virtual void Operation();
virtual void Add(Component* pChild);
virtual void Remove(Component* pChild);
virtual Component* GetChild(int nIndex);
private:
// 采用list容器去保存子组件
std::list m_ListOfComponent;
};
#endif
2)Composite.cpp
/**//*****************************************************/
created: 2006/07/20
filename: Composite.cpp
author: 李创
http://www.cppblog.com/converse/
purpose: Composite模式的演示代码
*********************************************************/
#include “Composite.h”
#include
#include
/**//*——————————————————————-
Component成员函数的实现
——————————————————————-*/
void Component::Add(Component* pChild)
{
}
void Component::Remove(Component* pChild)
{
}
Component* Component::GetChild(int nIndex)
{
return NULL;
}
/**//*——————————————————————-
Leaf成员函数的实现
——————————————————————-*/
void Leaf::Operation()
{
std::cout << “Operation by leaf\n”;
}
/**//*——————————————————————-
Composite成员函数的实现
——————————————————————-*/
Composite::~Composite()
{
std::list::iterator iter1, iter2, temp;
for (iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();
iter1 != iter2;
)
{
temp = iter1;
++iter1;
delete (*temp);
}
}
void Composite::Add(Component* pChild)
{
m_ListOfComponent.push_back(pChild);
}
void Composite::Remove(Component* pChild)
{
std::list::iterator iter;
iter = find(m_ListOfComponent.begin(), m_ListOfComponent.end(), pChild);
if (m_ListOfComponent.end() != iter)
{
m_ListOfComponent.erase(iter);
}
}
Component* Composite::GetChild(int nIndex)
{
if (nIndex <= 0 || nIndex > m_ListOfComponent.size())
return NULL;
std::list::iterator iter1, iter2;
int i;
for (i = 1, iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();
iter1 != iter2;
++iter1, ++i)
{
if (i == nIndex)
break;
}
return *iter1;
}
void Composite::Operation()
{
std::cout << “Operation by Composite\n”;
std::list::iterator iter1, iter2;
for (iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();
iter1 != iter2;
++iter1)
{
(*iter1)->Operation();
}
}
3)Main.cpp
/**//**************************************************/
created: 2006/07/20
filename: Main.cpp
author: 李创
http://www.cppblog.com/converse/
purpose: Composite模式的测试代码
*******************************************************/
#include “Composite.h”
#include
int main()
{
Leaf *pLeaf1 = new Leaf();
Leaf *pLeaf2 = new Leaf();
Composite* pComposite = new Composite;
pComposite->Add(pLeaf1);
pComposite->Add(pLeaf2);
pComposite->Operation();
pComposite->GetChild(2)->Operation();
delete pComposite;
system(“pause”);
return 0;
}