#
尊敬的公司领导:
您们好!
首先祝公司在新的一年中蓬勃发展,取得更加优异的成绩;祝愿公司上下所有领导和员工身体健康,万事如意!我为能在****工作过感到无比的荣幸和自豪,我会怀念在这里的每时每刻,感谢公司给了我这么一个机会。在公司这一年多里,公司领导和周围同事给了我无比的照顾和关怀,让我深切的感受到了公司倡导的人情化管理给我们带来的亲切和温馨。我深信,公司将沿着通往胜利彼岸的高速轨道飞速前进,将一如既往的在*******领域领航!
我是06年初带着满身激情来到北京的,原打算在我们伟大的首都能有一番作为,现在看来这些远大抱负都将离我远去了。也许我是一个弱者,不能去面对困难与挫折,没能很好的预料到即将到来的暴风雨,以至于现在让我措手不及,不敢面对,面对重重压力,我只能选择逃避。毕竟我不单单是我,我还有我的家庭,有我的父母和妻子,我不能太过于自私,不能为了自己的事业而忽略了他们的感受。一切的理想和抱负都是过眼云烟,在这繁忙的首都我终将迷失方向。回家过着一份安静平和与世无争的生活也许是我最好的选择。在家里我能照顾我年迈的双亲,能和妻子相濡以沫恩恩爱爱,能很好的养育我的孩子们,但是在北京这一切都无法做到,面对疯涨的房价,高额的房租,攀升的物价,想在北京安个家永远只是那些被上帝宠坏了的人所能实现的,而我只能痴心妄想。我不想眼睁睁的看着自己的双亲老去,而自己不能很好的尽到做儿子的职责,不想忍受等我有所成时子欲养而父不在的那种痛苦;我不想看着妻子和我在北京居无定所,瓢泼不定的一天天老去,这会让我一辈子永远愧对我的妻子;我不想让我的孩子在刚出生时就不知道他的爸爸在哪,不想让他成为时下最为关注的留守儿童,如果不能尽到一个父亲的责任,我会永远对不住我的孩子……所有这一切让我不得不重新考虑自己的人生,我想我最好的选择就是回家,虽然那会让我留下终生的遗憾,但是我想做一个好儿子,好丈夫,好爸爸比什么都更重要,况且回家我照样可以有自己的一番事业,是金子到哪都会闪光。
这段时间,我会把自己负责的****项目那块很好的完成,会把自己的活交接完毕。如果我的离去给公司带来了好多不便,我表示万分的歉意,希望公司领导考虑考虑我的实际情况给予理解。我真诚的恳请公司领导批准我的辞职申请,在这里我表示衷心的感谢,同时祝愿公司不断壮大发展!
此致
敬礼!
***:**
2007年3月13日
不知不觉做
华为外包项目已一年多了,曾在华为常驻过,也曾负责过项目的测试,感觉对华为外包项目的测试流程较熟悉,故写些心得来与大家分享。
如果竞标成功,项目就开始要启动了。
华为方会提供一份CRS(客户需求)和SOW(工作任务书),华为方派人过来进行需求培训,这时该项目的测试组长也要参与到项目需求的培训和评审,也就是测试工作应该从需求开始介入。
项目经理编写《项目计划》,开发人员产出《SRS》,这时测试组长就要根据SOW开始编写《测试计划》,其中包括人员,软件硬件资源,测试点,集成顺序,进度安排和风险识别等内容。
《测试计划》编写完成后需要进行评审,参与人员有项目经理,测试经理和华为方人员,测试组长需要根据评审意见修改《测试计划》,并上传到VSS上,由配置管理员管理。
待开发人员把《SRS》归纳好并打了基线,测试组长开始组织测试成员编写《测试方案》,测试方案要求根据《SRS》上的每个需求点设计出包括需求点简介,测试思路和详细测试方法三部分的方案。《测试方案》编写完成后也需要进行评审,评审人员包括项目经理,开发人员,测试经理,测试组长,测试成员和华为方;如果华为方不在公司,就需要测试组长把《测试方案》发送给华为进行评审,并返回评审结果。测试组长组织测试成员修改测试方案,直到华为方评审通过后才进入下个阶段――编写测试用例。
测试用例是根据《测试方案》来编写的,通过《测试方案》阶段,测试人员对整个系统需求有了详细的理解。这时开始编写用例才能保证用例的可执行和对需求的覆盖。测试用例需要包括测试项,用例级别,预置条件,操作步骤和预期结果。其中操作步骤和预期结果需要编写详细和明确。测试用例应该覆盖测试方案,而测试方案又覆盖了测试需求点,这样才能保证客户需求不遗漏。同样,测试用例也需要通过开发人员,测试人员和华为方的评审,测试组长也需要组织测试人员对测试用例进行修改,直到华为方评审通过。
在我们编写测试用例的阶段,开发人员基本完成代码的编写,同时完成单元测试。华为的外包项目一般是一次性集成,所以软件转测试部后直接进行系统测试。测试部对刚转过来的测试版本进行预测试,如果软件未实现CheckList清单上的10%,测试部会把该版本打回。否则,软件转测试部进行系统测试。根据《测试计划》进度安排,测试组长进行多轮次的测试,每轮测试完成后测试组长需要编写测试报告,其中包括用例执行通过情况,缺陷分布情况,缺陷产生原因,测试中的风险等等,这时测试人员就修改增加测试用例。待到开发修改完bug并转来新的测试版本,测试部开始进行第二轮的系统测试,首先回归完问题单,再继续进行测试,编写第二轮的测试报告,如此循环下去,直到系统测试结束。在系统测试期间,测试人员还需要编写验收手册,验收用例和资料测试用例等。
完成系统测试后,软件就开始转到华为进行验收测试,其中大概测试半个月,一般会要求测试部派人到华为方进行协助测试,并发回问题单给公司开发人员修改。
如果验收发现的缺陷率在SOW规定的范围内,那么验收成功,华为方付钱给公司,项目结束。如果超过规定的缺陷率,那么公司可能要罚钱了,整个项目组的成员(包括开发和测试)都可能要罚了。这种情况也会有,如果按照流程做事,概率不会很大。
测试流程的规范是很重要的,但是如果要成为优秀的测试人员只知道流程还是不够的,需要学习的东西还很多,包括熟悉相关测试业务,计算机专业知识(linux,oracle,tcp/ip等),开发的架构和语言,性能测试和系统瓶颈分析、调优等。还有性格(细心,耐心)和人际沟通能力也是很重要的决定条件。任重而道远,我刚起步,希望大家一起在测试的路上互励互勉。
本文结合自己的经验,从实践的角度,对项目软件的分析工作从7个方面进行了阐述,并指出一些容易失误的做法。希望能对从事分析工作的同仁有所参考。
软件从使用范围的角度,可分为项目软件和产品软件。
项目软件:即针对特定某个客户的要求,并仅为其使用的软件。又称工程软件,特点是有明确的合同,严格的工期,约定的维护期等。如"XXX公司XXX系统"。
产品软件:即针对某一领域客户的共有需求而开发的软件。特点是通用、功能丰富而冗余,通过一次性的购买行为获得等。如操作系统软件、数据库软件、CAD软件等。
本文就项目软件的需求分析,结合自身的体会,提出一些看法和建议。
1、 依据分析阶段确定合适的客户方配合人员
这一点对于获取真正的用户要求非常重要。通常,客户方会组织专工以上层次的人或在单位小有名气的计算机能手来和开发方分析人员配合,共同整理需求。
应该对客户方配合人员进行分类,层次化,使之和分析的各阶段相对应。
分析的初期,即总体分析阶段,需要得到整体意义上的轮廓需求,此时,应与客户方总工以上层次的人员进行交流,这一层次的人,对未来的系统会有完整的描绘,可以划分出子系统,及其之间的关系,这也是高级管理层对系统的期望。可以以此作为纲领性的文档指导进一步的分析,并约束后续的分析过程,避免需求范围漫无边际的扩大;
专业系统分析阶段,通常,客户单位都会有专业分工,彼此之间既相互独立,又会在某些点上发生联系。此阶段应与客户方专工层次的人员进行深入的讨论。这一层次的人,对自己的专业相当熟悉,对专业内的需求会非常到位,大都年富力强,有相当的阅历和理解能力,甚至自己都可以绘制业务流图,总结业务功能点。对他们应充分鼓励,尽量调动其积极性;
系统关联分析阶段,在各专业系统得到充分分析的基础上,紧接着就要理清它们之间的关系,这是提升需求档次的关键阶段,也是高级领导层和专工都关心的阶段。通常,客户单位都会有一些零散的软件,如财务软件,部颁软件等,这些专业软件都发挥着重要的作用,但都是些信息孤岛,客户会很自然的希望能把这些信息融合到整个系统中来,为更多的人所共享。同时,也希望数据能够在各专业系统间顺畅的流动,从而减少重复劳动,提高工作效率。此阶段应把总工层和专工层召集到一起,共同理清系统间的接口。
经过这三个阶段,对需求的描述将比较准确和完整。
2、 多方位描述同一需求
有一些需求贯穿了从基层人员到高层领导,对此需求应该从各个角度、各个方位给以描述,总结之后才能得到完整的表达,否则可能会漏掉一些信息。这也为后续的设计工作打好了基础。
比如,在设备管理类软件中,有一个概念叫"缺陷",指由于材料老化或外力作用,使得设备处于不正常的运行状态,但还没有到立刻就酿成"事故"的程度,但如不及时检修,就可能出事。对于设备缺陷业务,就涉及到从班组人员到领导,上上下下对此都非常关心,但各层次的人关心的侧重点却不尽相同:领导关心"消缺率"(即缺陷消除率)、"消缺及时率";专工关心缺陷类型和处理方法;班组人员关心消缺工作的人员安排及时间地点。缺陷的业务处理流程依赖于"设备缺陷单"(用于记录缺陷及消除情况),如果仅仅局限于从由基层得到的设备缺陷单上的数据结构(设备名称、缺陷发现人、发现时间、二级单位确认时间、缺陷性质、安排消缺时间、消缺人员、消除日期、处理方法),无法满足专工层的分析要求:对设备的缺陷情况按类型、零部件、型号、生产厂家等分类统计,为设备采购时作为选型参考、调整设备及其零部件的检修周期以减少缺陷发生的频率等,因此需要在原来的设备缺陷单上增加一些相关信息。
3、 清晰化每一数据项
由于需求将作为设计的基础,弄清所有的数据项的来龙去脉对于设计是必不可少的。不能有模糊不清的地方,同时通过对数据项来源的分析,可以让分析人员更清楚的看到数据的流动情况,也会发现一些新的需求点。
4、 充分挖掘潜在需求
由于分析人员对软件技术非常熟悉,一些由于技术所带来的潜在需求对于客户来说,一般很难被发现。不实现这些需求,对整个系统也没什么实质性的影响;实现这些需求,则会锦上添花。
对这些潜在需求,会有两种处理方式:告诉客户,客户会得到启发,可能进一步提出新的需求,会有一些更大胆的想法,从而扩大了需求范围,增加了工作量,甚至会影响到工期;不告诉客户,等客户想到了再说。
这些需求如果对于产品软件,可能会是一个卖点,要尽可能的去挖掘。但对项目软件,考虑各种风险,有时候可能会回避,或对客户隐瞒。
我觉得,不管是否告诉客户,分析人员还是应该去挖掘,最起码可以作为自己的知识积累。
5、 采用科学的分析报告模板
分析完成后,需要形成《需求分析报告》,应采用规范科学的报告模板,通过ISO或CMM的企业,其模板大都非常详尽,不仅仅作为报告模板,还可以指导分析过程。
比如,我所在的企业除了有规范的需求分析报告编写指南、报告模板,还有"需求分析矩阵"和"需求变更报告"用于管理需求和控制变更。
6、 积累领域知识
领域知识对于分析人员很重要,这些知识的广度和深度影响分析结果的准确性和分析进度。分析人员应该通过各种途径去获取这些,不断积累,并进行比较和总结。
7、 抱着学习与指导并存的态度
面对一个新的客户时,分析人员首先必须抱着谦逊的学习的态度,把这看成是丰富领域知识的机会。但并非客户单位的任何层次的人都有值得学习的东西,随着分析人员接触的领域客户不断增多,分析人员对该领域的理解也会越来越深,逐渐会成长为领域专家,会有很多地方超过客户对领域的理解,此时,要以自己的深入理解去指导客户,说服客户,甚至纠正客户的一些错误的认识,得到客户的信任与尊敬,这对迅速顺利的完成需求分析会很有帮助。
8、 误区
在进行需求分析的时候,容易陷入一些误区,导致分析结果不理想。
分析结果越复杂越好
这是技术型分析人员经常碰到的情况,认为分析出错综复杂的关系,花哨的图表才能显示出分析水平高,其实,分析经常要经历"简单-复杂-简单"的过程,前一个简单表现为分析人员"认为简单";随着分析的深入,原以为简单的问题会越来越复杂;最后,经过概括、消化、分解,使得需求简单明了。
必须一次到位
由于项目工期紧,或者客户单位地理位置偏远,不想反复去现场,希望通过一次需求分析就能得到完整的不再改变的结果。有这种情况时,表现为分析人员对客户方配合人员穷追猛问,或坚持要求配合人员做出保证,承诺需求范围不再扩大等等。结果往往是双方关系紧张,配合人员怕担责任,提出过多的灵活的、可配置的一些要求,无端增加了后续设计和编码的工作量。一次到位的想法是不现实的,随着开发工作的进行,用户经常会提出以前没想到的需求,或者更改已有的需求。需求必然有一个迭代的过程,变是不可避免的,关键是对于变化的控制,比如通过正规而繁复的流程提高需求变化时客户付出的代价:告知客户如此变化将会使工期延长,或需要追加资金等等,尽管对于"软件属于买方市场"的现状来说,开发方往往叫不起这个板,但这样的控制还是有一定的效果的。
客户的需求必须全部满足
陷入这一误区的分析人员,往往自己的领域知识欠缺,对客户的需求是否合理,缺乏分辨能力,只能由客户牵者走,这样会带来很大的风险:造成需求冗余,项目返工,更有对需求变化失去控制的危险,随着项目的开展,整个开发团队会越来越痛苦。所以必须加深自己的领域知识,变被动接受为主动引导,进而拒绝客户的不合理需求。
以上所述仅为个人体会,都是些做分析时的基本要求,要做好需求分析工作,还有赖于其他很多因素,如分析方法及辅助分析工具的掌握程度、个人交际能力的高低、语言沟通能力的高低等等,欢迎同行广泛交流,共同进步
中国人大都喜欢用武侠小说来比较软件开发,但是在实战武功中,只有葵花宝典才是最厉害的,也只有掌握了葵花宝典,才能称为“不败”。
但什么才是软件开发的葵花宝典? 让我们先从一些现象出发。我们的前提是,软件开发是一项智力密集型劳动。对于智力密集型劳动,我们观察到的现象是,个体的表现差异很大,团队的表现差异很大,组织的表现差异很大,国家的表现差异很大。这不象体力占主要的劳动,象百米王跑百米的速度也仅比我快50%。但在棋类运动中,一个高手可以车轮战数位低手,而且毫无例外地将他们一一击败!
这些智力运动员表现出的特点是,计算精确而且速度快。其行为很象东方不败。虽然关于葵花宝典的传说很多,但最准确的描述只有一个字“快”。东方不败已经快到了吓人的地步。就象卡斯帕罗夫已快到了深蓝的地步。
有一则关于物理学家玻尔的轶事,有一次玻尔在普林斯顿大学听两个年青教授演讲他们的工作成果。期间玻尔突然发言说,如果照你们的研究算下去,会得到一个很有意思的推论。结果两个年青教授回去计算了两天,果然得出了同样的结论。玻尔是如何做到这样快的?
在软件开发中,我们同样注意到这样一种高手,他们可以每天写出一千行左右的高品质代码。他们可以运用已有的一些软件包,迅速完成一个新的产品。他们可以在很短的时间内,学会一项新的程序语言或是新技术。他们表现出一种神奇的速度。
在武侠小说中,所有的高手都有一些凡人不能企及的表现。象张无忌学太极,用龙爪手击败龙爪手名家;乔峰用太祖长拳击败天下英雄;姑苏慕容以其人之道还治其人之身,令狐冲一剑剌瞎十几双眼睛等等。我认为,之所以他们能做到这样,关键是在于他们快。
快并不意味着不准或品质差。快与品质并不矛盾。
高手的快,其实包含着很高的品质在其中。如果你因为高手的快,就质疑其品质,那就相当于在问:东方不败出手那么快,会不会刺不准?东方不败并不满足于刺死对手,他会在对手身上刺朵花。他把杀人变成了艺术。准确来说,他真正的兴趣不在杀人,而在于艺术。
退一步说,就算东方不败第一击有点偏差,他稍作修正后,马上跟上的第二第三击,也会击中他想击中的地方。在武功差的对手剑还没拨出来的时候,他已杀死对方并刺上了一朵花。
所以真正的软件高手,他并不满足于他的代码能有效地工作了,他认为编程是艺术,并醉心于其中。在低手能写出一个版本的时间里,他已经写出了第十版。其品质当然不可同日而语。就象一个九段棋手,在给定的时间里,他能计算十种可能,并将每种可能计算到100手之后,从中选择一种最有利的下法。低手岂有苟全的机会?
高手写软件总是不停地在重构(refactoring)。高手喜欢迭代式开发。高手说,增量就是打补丁,迭代就是推倒重来。对于软件这种东西,写一遍它可能ok(做到这一点也不容易),写十遍就是一个伟大的产品,再多写一遍它就更伟大些。
高手快的诀窍在于他很熟悉各种东西。高手看书很快,因为每一本新书里,值得他好好看的新技术只有一两章的内容。他能迅速看完,并准确领会这本书的中心思想和价值。而对于一个新手,每句话都是新的,他都需要去理解,每一段例子,他都需要去试。
很少看到一种100%全新的技术或理论。就象java language specification里说的,java没有使用任何新技术,用的都是业界久经考验的技术。对于高手来说,那些技术都是他所熟悉的。自然,很快他就从一个c++高手变成了java高手。如果一个编程新手学java,学两年也不如一个高手学两个月的。高手学新东西快。
高手写代码速度快。统计结果说,人均每人月的有效代码速度大概是300至400行。但那是业界平均生产效率。对于高手来说,这个数字太低了。每天写300至400行是完全有可能的。因为在写代码时,所有知识都已具备,已经没有任何需要他多花时间的事情了。他甚至很少需要debug。
高手重用代码的能力很强,熟悉新的api的速度很快。这也是因为,他曾经使用过很多的api,重用过很多的代码。他知道哪些是可用的,哪些有缺陷。他既过用qt,也用过gtk+,也用过windows api & mfc,也用过awt & swing。新的api对他来说,也是老熟人。
高手喜欢用轻量级的工具,象vi,notepad,最多到ultraedit这样复杂的。高手用这种工具写出很多的东西。这些工具就象东方不败的针。那根针已具有神奇的魔力,有时候它可以当激光枪来用。
对于一些重量级的工具,高手虽不常用,但一经使出也威力大于常人。如果让东方不败用剑,最厉害的剑术名家也会败得很难看。高手其实用过很多的重量级工具,而且深知其优缺点。所以使出来,就会把威力发挥到最大,而把缺陷减少到最小。而低手则不然,总是把缺陷加以大大的发扬而浑不知其精髓何在。就象很多人学用uml、rup、xp、design pattern那样。
高手所学博杂且融会贯通。高手做什么都快,当低手还在一愁莫展的时候,高手已经圆满解决问题,去干别的事去了。
相信你有一点点想成为高手了。但是有一个问题亟等解决,那就是“欲练神功,必先自宫”的问题。这一点其实是有比喻意义的。就是说,你必需抛弃一些世俗的人们很看重的东西。有诗为证:
世人都晓高手好,只是寂寞受不了
世人都晓高手好, 只有名利忘不了
世人都晓高手好, 只有金钱一定要
世人都晓高手好, 天下美女都要抱
世人都晓高手好, 不写代码最最好
高手的武功不是一朝一夕练成的。还记得玻尔那件轶事吗,玻尔回答说,他年青时也计算过很多的问题。在很多计算的基础上,高手能培养起一种感觉。高手不写代码就能做设计是因为他以前写了很多的代码。而且他们会保持写代码,以保证自已的水平不下降。想一想九段高手是如何练成的。最难做到的是能忍受十年磨一剑的寂寞。别人在父母那里撒娇时,他们在一旁用功。十年磨一剑,剑就成了东方不败的针。
在你下定决心要做高手之后,也就是下定决心抛弃那些世俗的追求之后,也就是你下决心忍受那些来自于庸俗的人的白眼、攻击和谩骂之后,你就具备了练成神功的必要条件。
事实上其实你不必一开始就练神功,一开始大家可能是为了钱,房子,汽车,美女才编程序的,然而后来艺术就从中产生了。那时高手就不再关注那些东西了。卓别林曾说过,他开始进入那个圈子也是为了钱,后来艺术就从中产生了。当然,也有人一开始是为了艺术,后来变成为了钱。
所谓三十而立,就是说到了三十,你找到了你的真爱,值得用一生去追求的那种。比如说有的人到了三十认为这一辈子应该赚尽可能多的钱,这也没什么不好,也可以把赚钱本身变成一种艺术,所谓资本运作是也。所以在三十以前,有些私心杂念没什么。三十以后还这样是可耻的。而我,想做一个程序员。
每个人做自己最喜欢的事。这个世界需要程序员,也需要资本运作。所有真正的程序员,他最喜欢的事是编程和他自已。如果他后来去做ceo去了,不再编程,只说明他本来不是一个真正的程序员。
在成为高手的路上,要有热情,要循序渐进,要持之以恒。
要靠自己,书要快快地看。要试图迅速理解其主旨。其实你快快看所接受的信息量,与慢慢看接受的差不多。能明白多少很大程度上取决于你的功底。以后用到再回过头来看。一本对你来说新东西太多的书,不要指望看一次就全理解吸收。就象很多功力不够的人看design patterns那本书一样。慢慢看还不如找到多种 信息来源,都快快看一遍。对于一个完全陌生的领域,只看一本书很远远不够的。
要靠自已,事要快快做。有一个朋友,几年前我介绍他去玩玩linux,他也表示想玩,但他现在还没碰过。他失去了很多机会。
平时要有意识提高自己写代码的速度,其实你一天写15行有效代码,与你写50行有效代码,其品质是差不多的。你应该把那些业界平均水平抛诸脑后,把超越自己做为唯一目标。等到你写了很多各式各样的代码,你的水平就不一般了。一个老师曾向我介绍他的学英语的决窍,他说你去啃原版小说,啃到50 本,就和一般人有很大距离了。就是这个理。如果你写得太慢,怎么能写得多?水平怎么能提高?
要靠自己,学很多别人怕学的东西。低手总会说:这么多东西怎么学得过来啊。于是就少学或不学。这样就成不了高手了。高手有非常广的知识面,有很丰富的经验。知道很多低手不知道的事。玩过很多低手听都没听过的东西。
要靠自己,努力满足客户的各种需求。个人技能是在满足客户的各种需求的过程中提高的。比如你喜欢用delphi,客户说一定要用vb,那你就答应他,然后把自己培养成为vb的高手。用户的需求看似**,但对你是一个机会。
怎样才能做到看书快,写代码快,学新东西快,一个显而易见的途径就是将工作并行化。你在一台机器上make时,同时可以在看别的文档和聊天。对于计算机是这样,对人也是这样。如果你只能串行地处理问题,你的速度将提高有限。你的大脑有很大潜力可挖,它应该是一个多任务分时系统。努力减少它 idle的时间。搞经济的samuelson被人称为human brain main frame,可见他的大脑有多快。
让你的思维快起来,你就会区别于那些反应迟钝的人。如果你不能让人生的道路变长,就让它变宽。这世界变化快,需要你变得比它快才行。
这样加快并不会让你短命,相反,你有更多的时间来享受生活和锻炼身体。你的生活将更有品质,更丰富,更有意义。面对变化,你将立于不败之地。我们都是和自己赛跑的人,需要跑得比昨天的自己更快。
一、什么是系统分析
在具体的研究需求分析之前,我们先了解一下软件工程这个概念。软件工程分为三个层次,过程层、方法层、工具层。在最基础的过程层,最重要的就是一组被称为关键过程区域(KPAs)的框架(KPA的概念在讨论CMM的书中有详细的概念说明)。关键过程区域构成了软件项目的管理控制的基础,并且确立了上下文各区域的关系,其中规定了技术方法的采用、工程产品的,模型、文档、数据、报告、表格等,等的产生、里程碑的建立、质量的保证及变化的适当管理。方法层主要是过程在技术上的实现。它解决的问题是如何做。软件工程方法涵盖了一系列的任务:需求分析、设计、编程、测试、维护。同时他还包括了一组基本原则,控制了每一个的关键过程区域。工具层就很好理解了,他对过程层和方法层提供了自动和半自动的支持。这些辅助工具就称为CASE。事实上需求分析是跨越了软件工程的三个层次的。这一点是和其他的过程是一样的。
可以看到需求分析的位置,它是我们软件开发的第一步。是对用户需求的定义,对软件系统的描述。系统分析的任务:将用户的业务逻辑转化为程序逻辑,计算时间和成本。根据开发人员的理论知识和实际的经验,人们会采用各种满足实际情况的系统分析、开发方法、步骤以及文档等等。一般情况下,在系统分析书中应该有以下内容(视项目而定):
1、 系统需求说明 说明系统是一个什么样的系统,用市场上现有的系统来类比,用客户(或是我们自己)需要一个什么样的系统进行说明,力求完整。并对系统的发展可扩充性进行描述(现在没有哪个系统是一次OK的)。说明与现有的系统有什么相同什么不同,说明未来系统的发展方面以及可移值性等能预见的事情。
2、 系统资源说明 对系统所需要的软件、硬件资源进行说明。描述系统所需要的所有的TCO成本。包括人员、时间、设备、系统、一次性投入资金、持续性投入资金这样的所有资源。
3、 系统可行性分析 对系统的实施中的资源进行分析,说明投入的合理性和必然性,对其中的所有不可预见性的投入进行合理的量化说明,来说明系统的实施的可行性。
二、系统分析员与程序员
大家应该对这两个词很熟悉了,但是对词里包含的意义可能并不是特别清楚。首先必须说明的是,程序员和系统分析员不存在谁高级谁低级的分别,他们是两种职业,对职业技能的要求完全不同。所以厉害的程序员就是系统分析员的说法是不对的。当然,系统分析员的技能要求他必须要懂得如何写程序,但是他的重心在于如何把一个很大的项目切割成适合个人的小块,然后将这些小块组织起来。程序员的职责就是如何更好更快的实现这些小块。
三、系统分析的方法和工具
UML全称:Unified Modeling Language,统一建模语言,是面向对象的建模语言,主要用于软件系统的面向对象建模。
UML是以面向对象图的方式来描述任何类型的系统,具有很广泛的应用领域。特别是在建立软件系统模型中,它支持从系统需求、系统分析到系统设计的整个建模过程。由于UML建模是一门专门的科学,而我们这门课程的任务是数据库系统开发,所以对于UML我们将有限的注意力集中在认识UML各种图示上。
可以使用Rational Rose 2003来建立UML模型
1) 建立角色
2) 创建用例
3) 创建角色用例关系图
4) 创建时序图
5) 创建协作图
四、QQ文本图形留言器系统分析的实现举例
1)需求分析总体图:
2)各模块细分分析图:
显示模块需求分析图
查询模块需求分析图
添加数据模块需求分析图
安全设置模块分析图
系统设置模块分析图
3)基本功能模块流程图(举例)
在这样的分析基础上,再进行编程,我们就可以有规律可依,做到有条不紊了。
Java Excel是一开放源码项目,通过它Java开发人员可以读取Excel文件的内容、创建新的Excel文件、更新已经存在的Excel文件。使用该API非Windows操作系统也可以通过纯Java应用来处理Excel数据表。因为是使用Java编写的,所以我们在Web应用中可以通过JSP、Servlet来调用API实现对Excel数据表的访问。
现在发布的稳定版本是V2.0,提供以下功能:
- 从Excel 95、97、2000等格式的文件中读取数据;
- 读取Excel公式(可以读取Excel 97以后的公式);
- 生成Excel数据表(格式为Excel 97);
- 支持字体、数字、日期的格式化;
- 支持单元格的阴影操作,以及颜色操作;
- 修改已经存在的数据表;
现在还不支持以下功能,但不久就会提供了:
- 不能够读取图表信息;
- 可以读,但是不能生成公式,任何类型公式最后的计算值都可以读出;
应用示例
1 从Excel文件读取数据表
Java Excel API既可以从本地文件系统的一个文件(.xls),也可以从输入流中读取Excel数据表。读取Excel数据表的第一步是创建Workbook(术语:工作薄),下面的代码片段举例说明了应该如何操作:(完整代码见ExcelReading.java)
import java.io.*;
import jxl.*;
… … … …
try
{
//构建Workbook对象, 只读Workbook对象
//直接从本地文件创建Workbook
//从输入流创建Workbook
InputStream is = new FileInputStream(sourcefile);
jxl.Workbook rwb = Workbook.getWorkbook(is);
}
catch (Exception e)
{
e.printStackTrace();
}
|
一旦创建了Workbook,我们就可以通过它来访问Excel Sheet(术语:工作表)。参考下面的代码片段:
//获取第一张Sheet表
Sheet rs = rwb.getSheet(0);
|
我们既可能通过Sheet的名称来访问它,也可以通过下标来访问它。如果通过下标来访问的话,要注意的一点是下标从0开始,就像数组一样。
一旦得到了Sheet,我们就可以通过它来访问Excel Cell(术语:单元格)。参考下面的代码片段:
//获取第一行,第一列的值
Cell c00 = rs.getCell(0, 0);
String strc00 = c00.getContents();
//获取第一行,第二列的值
Cell c10 = rs.getCell(1, 0);
String strc10 = c10.getContents();
//获取第二行,第二列的值
Cell c11 = rs.getCell(1, 1);
String strc11 = c11.getContents();
System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType());
System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType());
System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType());
|
如果仅仅是取得Cell的值,我们可以方便地通过getContents()方法,它可以将任何类型的Cell值都作为一个字符串返回。示例代码中Cell(0, 0)是文本型,Cell(1, 0)是数字型,Cell(1,1)是日期型,通过getContents(),三种类型的返回值都是字符型。
如果有需要知道Cell内容的确切类型,API也提供了一系列的方法。参考下面的代码片段:
String strc00 = null;
double strc10 = 0.00;
Date strc11 = null;
Cell c00 = rs.getCell(0, 0);
Cell c10 = rs.getCell(1, 0);
Cell c11 = rs.getCell(1, 1);
if(c00.getType() == CellType.LABEL)
{
LabelCell labelc00 = (LabelCell)c00;
strc00 = labelc00.getString();
}
if(c10.getType() == CellType.NUMBER)
{
NmberCell numc10 = (NumberCell)c10;
strc10 = numc10.getValue();
}
if(c11.getType() == CellType.DATE)
{
DateCell datec11 = (DateCell)c11;
strc11 = datec11.getDate();
}
System.out.println("Cell(0, 0)" + " value : " + strc00 + "; type : " + c00.getType());
System.out.println("Cell(1, 0)" + " value : " + strc10 + "; type : " + c10.getType());
System.out.println("Cell(1, 1)" + " value : " + strc11 + "; type : " + c11.getType());
|
在得到Cell对象后,通过getType()方法可以获得该单元格的类型,然后与API提供的基本类型相匹配,强制转换成相应的类型,最后调用相应的取值方法getXXX(),就可以得到确定类型的值。API提供了以下基本类型,与Excel的数据格式相对应,如下图所示:
每种类型的具体意义,请参见Java Excel API Document。
当你完成对Excel电子表格数据的处理后,一定要使用close()方法来关闭先前创建的对象,以释放读取数据表的过程中所占用的内存空间,在读取大量数据时显得尤为重要。参考如下代码片段:
//操作完成时,关闭对象,释放占用的内存空间
rwb.close();
|
Java Excel API提供了许多访问Excel数据表的方法,在这里我只简要地介绍几个常用的方法,其它的方法请参考附录中的Java Excel API Document。
Workbook类提供的方法
1. int getNumberOfSheets()
获得工作薄(Workbook)中工作表(Sheet)的个数,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
int sheets = rwb.getNumberOfSheets();
|
2. Sheet[] getSheets()
返回工作薄(Workbook)中工作表(Sheet)对象数组,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
Sheet[] sheets = rwb.getSheets();
|
3. String getVersion()
返回正在使用的API的版本号,好像是没什么太大的作用。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
String apiVersion = rwb.getVersion();
|
Sheet接口提供的方法
1) String getName()
获取Sheet的名称,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
String sheetName = rs.getName();
|
2) int getColumns()
获取Sheet表中所包含的总列数,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsColumns = rs.getColumns();
|
3) Cell[] getColumn(int column)
获取某一列的所有单元格,返回的是单元格对象数组,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell[] cell = rs.getColumn(0);
|
4) int getRows()
获取Sheet表中所包含的总行数,示例:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
int rsRows = rs.getRows();
|
5) Cell[] getRow(int row)
获取某一行的所有单元格,返回的是单元格对象数组,示例子:
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell[] cell = rs.getRow(0);
|
6) Cell getCell(int column, int row)
获取指定单元格的对象引用,需要注意的是它的两个参数,第一个是列数,第二个是行数,这与通常的行、列组合有些不同。
jxl.Workbook rwb = jxl.Workbook.getWorkbook(new File(sourcefile));
jxl.Sheet rs = rwb.getSheet(0);
Cell cell = rs.getCell(0, 0);
|
2 生成新的Excel工作薄
下面的代码主要是向大家介绍如何生成简单的Excel工作表,在这里单元格的内容是不带任何修饰的(如:字体,颜色等等),所有的内容都作为字符串写入。(完整代码见ExcelWriting.java)
与读取Excel工作表相似,首先要使用Workbook类的工厂方法创建一个可写入的工作薄(Workbook)对象,这里要注意的是,只能通过API提供的工厂方法来创建Workbook,而不能使用WritableWorkbook的构造函数,因为类WritableWorkbook的构造函数为protected类型。示例代码片段如下:
import java.io.*;
import jxl.*;
import jxl.write.*;
… … … …
try
{
//构建Workbook对象, 只读Workbook对象
//Method 1:创建可写入的Excel工作薄
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile));
//Method 2:将WritableWorkbook直接写入到输出流
/*
OutputStream os = new FileOutputStream(targetfile);
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(os);
*/
}
catch (Exception e)
{
e.printStackTrace();
}
|
API提供了两种方式来处理可写入的输出流,一种是直接生成本地文件,如果文件名不带全路径的话,缺省的文件会定位在当前目录,如果文件名带有全路径的话,则生成的Excel文件则会定位在相应的目录;另外一种是将Excel对象直接写入到输出流,例如:用户通过浏览器来访问Web服务器,如果HTTP头设置正确的话,浏览器自动调用客户端的Excel应用程序,来显示动态生成的Excel电子表格。
接下来就是要创建工作表,创建工作表的方法与创建工作薄的方法几乎一样,同样是通过工厂模式方法获得相应的对象,该方法需要两个参数,一个是工作表的名称,另一个是工作表在工作薄中的位置,参考下面的代码片段:
//创建Excel工作表
jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);
|
"这锅也支好了,材料也准备齐全了,可以开始下锅了!",现在要做的只是实例化API所提供的Excel基本数据类型,并将它们添加到工作表中就可以了,参考下面的代码片段:
//1.添加Label对象
jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell");
ws.addCell(labelC);
//添加带有字型Formatting的对象
jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true);
jxl.write.WritableCellFormat wcfF = new jxl.write.WritableCellFormat(wf);
jxl.write.Label labelCF = new jxl.write.Label(1, 0, "This is a Label Cell", wcfF);
ws.addCell(labelCF);
//添加带有字体颜色Formatting的对象
jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false,
UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED);
jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc);
jxl.write.Label labelCFC = new jxl.write.Label(1, 0, "This is a Label Cell", wcfFC);
ws.addCell(labelCF);
//2.添加Number对象
jxl.write.Number labelN = new jxl.write.Number(0, 1, 3.1415926);
ws.addCell(labelN);
//添加带有formatting的Number对象
jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##");
jxl.write.WritableCellFormat wcfN = new jxl.write.WritableCellFormat(nf);
jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN);
ws.addCell(labelNF);
//3.添加Boolean对象
jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false);
ws.addCell(labelB);
//4.添加DateTime对象
jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date());
ws.addCell(labelDT);
//添加带有formatting的DateFormat对象
jxl.write.DateFormat df = new jxl.write.DateFormat("dd MM yyyy hh:mm:ss");
jxl.write.WritableCellFormat wcfDF = new jxl.write.WritableCellFormat(df);
jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF);
ws.addCell(labelDTF);
|
这里有两点大家要引起大家的注意。第一点,在构造单元格时,单元格在工作表中的位置就已经确定了。一旦创建后,单元格的位置是不能够变更的,尽管单元格的内容是可以改变的。第二点,单元格的定位是按照下面这样的规律(column, row),而且下标都是从0开始,例如,A1被存储在(0, 0),B1被存储在(1, 0)。
最后,不要忘记关闭打开的Excel工作薄对象,以释放占用的内存,参见下面的代码片段:
//写入Exel工作表
wwb.write();
//关闭Excel工作薄对象
wwb.close();
|
这可能与读取Excel文件的操作有少少不同,在关闭Excel对象之前,你必须要先调用write()方法,因为先前的操作都是存储在缓存中的,所以要通过该方法将操作的内容保存在文件中。如果你先关闭了Excel对象,那么只能得到一张空的工作薄了。
3 拷贝、更新Excel工作薄
接下来简要介绍一下如何更新一个已经存在的工作薄,主要是下面二步操作,第一步是构造只读的Excel工作薄,第二步是利用已经创建的Excel工作薄创建新的可写入的Excel工作薄,参考下面的代码片段:(完整代码见ExcelModifying.java)
//创建只读的Excel工作薄的对象
jxl.Workbook rw = jxl.Workbook.getWorkbook(new File(sourcefile));
//创建可写入的Excel工作薄对象
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(targetfile), rw);
//读取第一张工作表
jxl.write.WritableSheet ws = wwb.getSheet(0);
//获得第一个单元格对象
jxl.write.WritableCell wc = ws.getWritableCell(0, 0);
//判断单元格的类型, 做出相应的转化
if(wc.getType() == CellType.LABEL)
{
Label l = (Label)wc;
l.setString("The value has been modified.");
}
//写入Excel对象
wwb.write();
//关闭可写入的Excel对象
wwb.close();
//关闭只读的Excel对象
rw.close();
|
之所以使用这种方式构建Excel对象,完全是因为效率的原因,因为上面的示例才是API的主要应用。为了提高性能,在读取工作表时,与数据相关的一些输出信息,所有的格式信息,如:字体、颜色等等,是不被处理的,因为我们的目的是获得行数据的值,既使没有了修饰,也不会对行数据的值产生什么影响。唯一的不利之处就是,在内存中会同时保存两个同样的工作表,这样当工作表体积比较大时,会占用相当大的内存,但现在好像内存的大小并不是什么关键因素了。
一旦获得了可写入的工作表对象,我们就可以对单元格对象进行更新的操作了,在这里我们不必调用API提供的add()方法,因为单元格已经于工作表当中,所以我们只需要调用相应的setXXX()方法,就可以完成更新的操作了。
尽单元格原有的格式化修饰是不能去掉的,我们还是可以将新的单元格修饰加上去,以使单元格的内容以不同的形式表现。
新生成的工作表对象是可写入的,我们除了更新原有的单元格外,还可以添加新的单元格到工作表中,这与示例2的操作是完全一样的。
最后,不要忘记调用write()方法,将更新的内容写入到文件中,然后关闭工作薄对象,这里有两个工作薄对象要关闭,一个是只读的,另外一个是可写入的。
要往xls文件里面写入数据的时候需要注意的是第一要新建一个xls文件
OutputStream os=new FileOutputStream("c:\\excel2.xls");
再建完这个文件的时候再建立工作文件
jxl.write.WritableWorkbook wwb = Workbook.createWorkbook(new File(os));
如果这个文件已经存在,那么我们可以在这个文件里面加入一个sheet为了和以前的数据进行分开;
jxl.write.WritableSheet ws = wwb.createSheet("Test Sheet 1", 0);
在createSheet方法里前面的参数是sheet名,后面是要操作的sheet号
接下来就可以往这个文件里面写入数据了
写入数据的时候注意的格式
(1)添加的字体样式
jxl.write.WritableFont wf = new jxl.write.WritableFont(WritableFont.TIMES, 18, WritableFont.BOLD, true);
WritableFont()方法里参数说明:
这个方法算是一个容器,可以放进去好多属性
第一个: TIMES是字体大小,他写的是18
第二个: BOLD是判断是否为斜体,选择true时为斜体
第三个: ARIAL
第四个: UnderlineStyle.NO_UNDERLINE 下划线
第五个: jxl.format.Colour.RED 字体颜色是红色的
jxl.write.WritableCellFormat wcfF = new jxl.write.WritableCellFormat(wf);
jxl.write.Label labelC = new jxl.write.Label(0, 0, "This is a Label cell",wcfF);
ws.addCell(labelC);
在Label()方法里面有三个参数
第一个是代表列数,
第二是代表行数,
第三个代表要写入的内容
第四个是可选项,是输入这个label里面的样式
然后通过写sheet的方法addCell()把内容写进sheet里面。
(2)添加带有formatting的Number对象
jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##");
(3)添加Number对象
(3.1)显示number对象数据的格式
jxl.write.NumberFormat nf = new jxl.write.NumberFormat("#.##");
jxl.write.WritableCellFormat wcfN = new jxl.write.WritableCellFormat(nf);
jxl.write.Number labelNF = new jxl.write.Number(1, 1, 3.1415926, wcfN);
ws.addCell(labelNF);
Number()方法参数说明:
前两上表示输入的位置
第三个表示输入的内容
(4)添加Boolean对象
jxl.write.Boolean labelB = new jxl.write.Boolean(0, 2, false);
ws.addCell(labelB);
(5)添加DateTime对象
jxl.write.DateTime labelDT = new jxl.write.DateTime(0, 3, new java.util.Date());
ws.addCell(labelDT);
DateTime()方法的参数说明
前两个表示输入的位置
第三个表示输入的当前时间
(6)添加带有formatting的DateFormat对象
这个显示当前时间的所有信息,包括年月日小时分秒
jxl.write.DateFormat df = new jxl.write.DateFormat("dd MM yyyy hh:mm:ss");
jxl.write.WritableCellFormat wcfDF = new jxl.write.WritableCellFormat(df);
jxl.write.DateTime labelDTF = new jxl.write.DateTime(1, 3, new java.util.Date(), wcfDF);
ws.addCell(labelDTF);
(7)添加带有字体颜色Formatting的对象
jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL, 10, WritableFont.NO_BOLD, false,UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.RED);
jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc);
import="jxl.format.*
jxl.write.WritableFont wfc = new jxl.write.WritableFont(WritableFont.ARIAL,20,WritableFont.BOLD,false,UnderlineStyle.NO_UNDERLINE,jxl.format.Colour.GREEN);
(8)设置单元格样式
jxl.write.WritableCellFormat wcfFC = new jxl.write.WritableCellFormat(wfc);
wcfFC.setBackGround(jxl.format.Colour.RED);//设置单元格的颜色为红色
wcfFC = new jxl.write.Label(6,0,"i love china",wcfFC);
代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> New Document </TITLE>
<META NAME="Generator" CONTENT="EditPlus">
<META NAME="Author" CONTENT="">
<META NAME="Keywords" CONTENT="">
<META NAME="Description" CONTENT="">
</HEAD>
<BODY>
<script language="javascript">
todayDate = new Date();
date = todayDate.getDate();
month= todayDate.getMonth() +1;
year= todayDate.getYear();
document.write(" 今天是")
document.write("<br>")
if(navigator.appName == "Netscape")
{
document.write(1900+year);
document.write("年");
document.write(month);
document.write("月");
document.write(date);
document.write("日");
document.write("<br>")
}
if(navigator.appVersion.indexOf("MSIE") != -1)
{
document.write(year);
document.write("年");
document.write(month);
document.write("月");
document.write(date);
document.write("日");
document.write("<br>")
}
if (todayDate.getDay() == 5) document.write(" 星期五")
if (todayDate.getDay() == 6) document.write(" 星期六")
if (todayDate.getDay() == 0) document.write(" 星期日")
if (todayDate.getDay() == 1) document.write(" 星期一")
if (todayDate.getDay() == 2) document.write(" 星期二")
if (todayDate.getDay() == 3) document.write(" 星期三")
if (todayDate.getDay() == 4) document.write(" 星期四")
</script>
</BODY>
</HTML>
源代码解释:
todayDate = new Date();
|
当定义一个新的对象时,通常使用“new”操作符。在这里,就是创建了日期对象。 |
date = todayDate.getDate();
|
getDate()是Date对象的一种方法,其功能是获得当前的日期。 |
month= todayDate.getMonth() + 1 ; ; |
getMonth()是Date对象的一种方法,其功能是获得当前的日期,由于月份是从0开始的,所以这里要“+1”。 |
year= todayDate.getYear() |
getYear()是Date对象的一种方法,其功能是获得当前的年份。 |
document.write("今天是") document.write("<br>") |
输出“今天是” |
if(navigator.appName == "Netscape") { document.write(1900+year); document.write("年"); document.write(month); document.write("月"); document.write(date); document.write("日"); document.write("<br> ") } |
如果浏览器是Netscape,输出今天是“year”+“年”+“month”+“月”+“date”+“日”,其中年要加1900。 |
if(navigator.appVersion.indexOf("MSIE") != -1) { document.write(year); document.write("年"); document.write(month); document.write("月"); document.write(date); document.write("日"); document.write("<br> ") } |
如果浏览器是IE,直接输出今天是“year”+“年”+“month”+“月”+“date”+“日”。 |
document.write("") ; |
在“日期”与“星期”之间输入一个空格。 |
if (todayDate.getDay() == 5) document.write("星期五"); if (todayDate.getDay() == 6) document.write("星期六"); if (todayDate.getDay() == 0) document.write("星期日"); if (todayDate.getDay() == 1) document.write("星期一"); if (todayDate.getDay() == 2) document.write("星期二"); if (todayDate.getDay() == 3) document.write("星期三"); if (todayDate.getDay() == 4) document.write("星期四") |
getDay()是Date对象的一种方法,其功能是获得当前是星期几。document.write输出今天是“星期几”。 |
|
一,其实随机色就是RGB分别取三个0-256的随机数,
然后把你想要改的对象的样式设置成这种颜色就行了。
var
rndColor
=
"
rgb(
"
+
Math.round(Math.random()
*
256
)
+
"
,
"
+
Math.round(Math.random()
*
256
)
+
"
,
"
+
Math.round(Math.random()
*
256
)
+
"
)
"
;
document.getElementById(
"
myData
"
).style.color
=
rndColor;
二,利用javascript中的setInterval()函数,定时给某一个控件(如:span)的更换字体颜色样式。
在javascript中,element.style.color属性允许使用rgb(x,y,z)函数,这样我们就可以生成三个随机数填充,以达到随机 变颜色的效果。我们可以用Math.random()来获得随机数,然后再利用Math.round()来得到一个小于当前值的最大整数。
RGB的值的随机范围是0-255,所以每个随机值是:Math.round(Math.random()*256)。
<span id="myData">Hello world</span>
<script language="javascript">
window.onload = function(){
setInterval( rndMyData, 1000 );
}
function rndMyData(){
var rndColor = "rgb(" + Math.round(Math.random()*256) + "," + Math.round(Math.random()*256) + "," + Math.round(Math.random()*256) + ")";
document.getElementById( "myData" ).style.color = rndColor;
}
</script>
很多架构师都是从好的开发人员逐步过渡而来的,但并非每个好的开发人员都希望成为架构师,而且他们并不是都适合做架构师。无论您是打算进行职业转型的开发人员,还是寻找能承担体系结构设计责任的合适人选的经理,都务必对此转型过程有个清楚的了解。本文将讨论从实现专家到架构师的过渡过程。
在寻找优秀的指挥的时候,您首先要找的是一名优秀的音乐演奏家。但并非每个音乐演奏家都能成为优秀的指挥。架构师的专业发展方面也与此类似。越来越多的 IT 组织开始认识到良好软件体系结构的重要性,架构师职业正迅速发展为 IT 内一个独立的门类。由于要从相当小的候选范围内招募架构师,因此这就给管理带来了一些新挑战。即使人力资源部门找到了候选者,针对经验进行的筛选也比其他门类更为严格。跨越这些障碍的最快方式是要认识到,大部分好的架构师同时也是好的开发人员,因此寻找架构师人才时可能首先应该从普通开发人员中找起。招聘人员在对候选者(内部或外部)进行详细审查时,应该考虑这个观点。不过,对此资源进行挑选可能比较麻烦,因为只有极少的优秀开发人员具有成为架构师的特征或愿望。
本文列出了开发人员成为架构师要进行的工作。我将从可能考虑进行此转型的开发人员和评估进行此转型的开发人员的经理这两个方面来探讨这一问题。我还将提供一系列在做出这些决策时要考虑的因素。
个人特征
软件开发团队和管理层之间的联系始终是 IT 中的一个关键所在。二者都倾向于以完全不同的方式考虑给定的问题。大部分相关技术都是讨论项目经理应如何跟踪和解释开发人员的进度和问题。但沟通不足的情况仍然非常普遍,而且这是项目失败的首要原因。好的架构师是解决这个问题的最有效办法。架构师的主要责任是提供开发人员和项目经理之间的共用沟通媒体。他们负责让业务规则及需求与工程实践及限制相适应,以确保成功。以下是成功架构师的一些主要特征。
愿意并有能力进行沟通:在开发人员中发现架构师的最有价值标准是有效的沟通。您需要技术娴熟、经验丰富的开发人员,这样的人员需要有就项目中的业务相关问题进行沟通的经历。架构师经常必须对理解方面的差距进行预计,然后才能有所贡献。他们必须愿意克服困难来确保技术和业务观点的融合。他们并不必对意见交换工作进行计划和协调;这仍然主要是项目经理的工作。他们的任务是确定表述系统设计时的最佳工具和构件,以促进有效的意见交换。他们必须能够判断当前方法显得不足而需要采用新方法的情况。写作技能也非常重要,还需要具有制作草图的技能或使用制图软件的能力。
具有处理谈判细节方面的经验:架构师经常需要负责讨论系统开发的技术折衷方案。优先级的冲突可能会带来实践限制、风险规避或可能导致在各个不同业务组之间需求不同。优秀的架构师能够有效地评估技术可能性,并能在不损失项目的主要价值的前提下制订开发计划来处理各种利害关系和限制。这与前面讨论的沟通技能紧密相关,但同时也要体现架构师的技术能力。好的架构师候选者应该是经常帮助对有争议的讨论进行引导的人,能够使讨论得出新的想法,而不会使其在一个位置停滞不前。
自觉主动;积极解决设计问题:架构师的日常工作目标经常并不明确。很多开发人员直接参考功能规范来列出任务清单。架构师通常则是向这些开发人员提供所需结构的人员,以便尽可能提高工作效率。好的候选者不仅进行沟通方面的工作,而且也会预计各种设计问题并加以解决——通常在没有任何具体指示的情况下自觉进行。无论所分配的职责如何,积极参与项目的开发人员都有机会从一起工作的人员中脱颖而出。
抽象思维和分析:架构师必须能够理解表述模糊的概念并将其变成相关各方能够理解的项目构件。他们必须能够理解抽象概念,并以具体的语言对其进行沟通。开发人员中好的候选者经常要求或自己主动解释开发生命周期中容易混淆的问题。他们能迅速评估各种想法并将其纳入后续工作的操作建议中。
开发人员经常具有很强的数学能力,而好的架构师则倾向于表现出更强的口头表达能力。管理人员经常说开发人员具有“工程意识”,而这是一个用于评估架构师的非常有意义的方面。架构师应该具有很强的解决技术问题的能力,但还必须能够准确获知更为全面的人员如何与技术交互的信息。这要求具有某种形式的抽象思维(而不再是代码的细节),这种思维能力可能较难形成。
有些人认为,某种级别的正式教育是成为优秀开发人员的必备条件之一,我并不同意这种精英论。我遇到了很多高中就辍学的优秀开发人员。不过,对于体系结构设计工作,我的个人经验以及我对所需能力的认识都让我相信,好的架构师通常至少获得了一个有挑战性的学士学位。
跟踪生命周期
好的架构师通常有在具备定义良好的软件开发生命周期(Software Development Life Cycle,SDLC)的组织工作的经验。架构师必须理解在其所属专业内最重要的操作过程。这并不意味着需要有其他前提,例如,并不需要高能力成熟度模型(Capability Maturity Model,CMM)级别的工作经验。好的架构师可能来自使用 SDLC 的多个小型迭代的极限编程(Extreme Programming,XP)方法的组织。务必注意各种传统软件开发操作,如 Michael A. Jackson 的方法:Jackson 结构编程(Jackson Structured Programming,JSP)和 Jackson 系统开发(Jackson System Development,JSD)。Jackson 的研究对架构师职业发展的意义就像 Donald Knuth 的研究对程序员一样重要。架构师可以偏爱任何经典的、经过时间考验的软件系统开发方法。
SDLC 也可以成为评估架构师合适人选的有用机制。每个 SDLC 阶段都具有能提供相关线索的特征。SDLC 包含很多小的变体,但在此部分,我将使用几乎所有方法的公共基础部分。下面的列表详细说明了 SDLC 的各个阶段,并列出了好的架构师候选者在每个阶段表现出来的特征。
- 分析:在分析期间,好的架构师会考虑非技术影响,以便了解需求和将在其中进行开发的环境。架构师可为风险评估任务带来广泛的软件经验供参考。寻找具有丰富经验的开发人员,以帮助业务部门理解技术人员正确解释需求所需的信息。寻找在开发的早期阶段能够预计可能遇到的问题的开发人员。
- 设计:在高级设计期间,好的架构师会收集问题空间的各个抽象元素,并就其进行沟通,以便开发团队草拟将要开发的系统的相关图表。架构师负责将需求谨慎地映射到所得到的系统体系结构的功能。在详细设计期间,他们所扮演的角色并不是核心角色,但为了根据整个系统的规则对特定模块的元素进行审查,仍然需要他们。寻找善于让团队能够预计设计决策对最终系统的影响的开发人员。寻找善于确定一些最佳构件来促进与技术和非技术受众沟通设计问题的开发人员。
- 实现:在实现期间,架构师对项目进行引导,以确保其符合系统体系结构。他们在一线评估技术更改请求,并确定如何对设计进行调整,以最好地处理此类请求。架构师还要密切了解开发人员的进度,特别要跟踪系统中模块间的集成点的状态。寻找经常对讨论进行引导来连接多个子系统的开发人员。寻找项目经理可以依赖其快速地进行与更改和出现的问题相关的风险评估的开发人员。
- 测试:架构师对系统集成和用户接受度测试进行指导,并负责评估进度的正确沟通的持续测试结果。寻找理解错误模式且善于将测试复查结果转换为行动计划的开发人员。
- 维护:在维护期间,架构师将发起关于系统集成的讨论。无论处理 IT 基础设施问题,还是确保部门之间的技术合作,架构师都必须完全理解应用程序,必须快速学习姊妹应用程序的体系结构,而且必须就集成点和风险进行有效沟通。寻找具有系统集成经验且表现出快速掌握全貌的能力的开发人员。系统集成是一项独特的任务。
架构师培养建议
有些组织能比其他组织更有效地进行架构师培养。如果充分考虑到招聘此类新专业人才的困难,努力促成能鼓励开发人员发展为架构师的环境是非常明智的策略。但务必避免对不愿意或不适合走这条路的开发人员进行处罚。组织应该为开发人员制订多条发展路线,包括那些愿意继续担任开发人员的人。对架构师而言,资深开发人员不可或缺。他们可以实现系统中最关键的模块。通过对其他开发人员进行代码检查和测试支持,他们可帮助确保总体软件质量,而如果质量不能保证,即使最好的体系结构也毫无用处。
组织应制订个人评估程序,以鼓励开发人员考虑其职业目标,其中要包含体系结构设计的选项。应该鼓励经理在其下属中寻找体系结构设计人才。应该实现指导计划,让架构师与希望成为架构师的开发人员协作工作。应该鼓励开发人员通过参加各种协会、撰写文章和参加会议,从而参与到专业领域中来。通过这样参与进来,可帮助开发人员从新的角度理解系统,并帮助他们更好地就其认识进行沟通。这样还能培养可提高效率的重要创新想法。
结束语
开发人员一旦迈出了通向体系结构设计专业方向的第一步,就可以利用很多资源来获得帮助,其中包括很多来自 IBM 的资源。有时候,此过程的最困难的部分就是第一步,而本文提供了一些线索和提示,经理和开发人员可以利用其来评估应该鼓励哪些人努力成为架构师。