??xml version="1.0" encoding="utf-8" standalone="yes"?> 问题Q由于log4cpp-0.3.5rc3仅提供了vc6的工E文Ӟ因此Q用vs2005打开后,需要进行{换。但是{换后Q不能正编译,提示Custom Build Step时出C错误?/p>
分析Q因为log4cpp在生成NTEventLogAppender.dllӞ需要连接NTEventLogCategories.mc文g。所以,目讄了自定义的生成步骤去生成NTEventLogAppender.dll。但从vc6的工E文件{换时Q这些步骤却没有正确的{换过来。从而出Cq问题?/p>
解决ҎQ重新填写Custom Build StepV?/p>
其中QCommandLine填写以下内容Q?/p>
if not exist $(OutDir) md $(OutDir) Outputs填写Q?(OutDir)\NTEventLogAppender.dll 适用范围Qlog4cpp目、log4cppDLL目的Debug和Release配置。同Ӟ该方法适用于vs2003(vc7.1)?/p>
不在同一个包内的参与者、用例、类、构件和包,名称可以相同。不同的模型元素拥有相同的名U时Q这些元素被UCؓ“重载?br />重蝲允许你进行基于多语言构g的开发?br />重蝲允许用例视图中的参与者和逻辑视图中的cL有相同的名称
如果在其它包中存在具有相同名U的设计元素Q系l会提示你,此时点“确定”即?br /> 逻辑视图:描述pȝ设计模型Q包含与pȝl构最重要意义的部分,比如Q系l分解成为的子系l,子系l分解成多个c,以及q些元素的职责,关系Q操作和属?/p>
q程视图Q描q系l分解成U程及进E的q程Q描q线E(q程Q通讯模试{?/p>
部v视图Q描q运行系l的物理gQ包含网l)配置Q说明每个节点的计算机,CPUQ操作系l以及它们互联的情况Q还要包括进E到节点之间的映关pR?/p>
实施视图Q描q系l在构徏时的分解后的子系l(包)的情况,特别是包括哪些组成部分由哪些团队开发,以及购入Q外包,开发进度等内容。项目经理应该对q个视图最感兴?br />使用vs2005(vc8)~译log4cpp-0.3.5rc3
"mc.exe" -h $(OutDir) -r $(OutDir) $(SolutionDir)NTEventLogCategories.mc
"RC.exe" -r -fo $(OutDir)\$(InputName).res $(ProjectDir)\$(InputName).rc
"link.exe" /MACHINE:IX86 -dll -noentry -out:$(OutDir)\NTEventLogAppender.dll $(OutDir)\$(InputName).res
在利用Rational Rose对系l徏模时Q可能会遇到同一个被建模的对象在不同包中h不同职责的问题?br />比如Q“用户”这个对象,在业务领域模型中Q它是一个业务工人或业务主角(business actor)Q在pȝ用例模型中,我们需要创建另一个代表系l执行者(Actor)的元素。Rational Rose以名U标识不同的模型元素Q似囑ֆ创徏一个叫"用户"的Actor则会成重名?br />q各重名Q可以称为元素“重载”?br />
下面介绍如何q行“元素重载?br />
创徏一个重载元?br />1Q从工具׃创徏一个新的元?br />2Q双L元素Q或者单击Browse>SpecificationQ打开规范H口
3Q在名称字段中输入名U?br />4Q单击OK按钮 转注:
今天有网友问到这个问?于是在网上搜索了一?转脓q此.怼的太多了,出处不详.在此感谢原作者精彩讲?
一、预备知识—程序的内存分配
一个由c/C++~译的程序占用的内存分ؓ以下几个部分
1、栈区(stackQ— 由~译器自动分配释放 ,存放函数的参数|局部变量的值等。其操作方式cM于数据结构中的栈?
2、堆区(heapQ — 一般由E序员分配释放, 若程序员不释放,E序l束时可能由OS回收 。注意它与数据结构中的堆是两回事Q分配方式倒是cM于链表,呵呵?
3、全局区(静态区Q(staticQ—,全局变量和静态变量的存储是放在一块的Q初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在盔R的另一块区域。? E序l束后有pȝ释放
4、文字常量区 —常量字W串是攑֜q里的。 程序结束后ql释?
5、程序代码区—存攑ևC的二q制代码?
二、例子程?
q是一个前辈写的,非常详细 //main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区?br />
main()
{
int b;// 栈?/span>
char s[] = "abc"; //栈?/span>
char *p2; //栈?/span>
char *p3 = "123456"; 123456\0";//在常量区Qp3在栈上。?/span>
static int c =0Q?/span>//全局Q静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得来?0?0字节的区域就在堆区。?/span>
strcpy(p1, "123456"); //123456\0攑֜帔R区,~译器可能会它与p3所指向?123456"优化成一个地斏V?/span>
}
三、堆和栈的理论知?
3.1甌方式
stack:
ql自动分配。 例如,声明在函C一个局部变量 int b; pȝ自动在栈中ؓb开辟空?
heap:
需要程序员自己甌Qƈ指明大小Q在c中malloc函数
如p1 = (char *)malloc(10);
在C++中用newq算W?
如p2 = (char *)malloc(10);
但是注意p1、p2本n是在栈中的?
3.2 甌后系l的响应
栈:只要栈的剩余I间大于所甌I间Q系l将为程序提供内存,否则报异常提示栈溢出?
堆:首先应该知道操作pȝ有一个记录空闲内存地址的链表,当系l收到程序的甌Ӟ
会遍历该链表Q寻扄一个空间大于所甌I间的堆l点Q然后将该结点从I闲l点链表中删除,q将该结点的I间分配l程序,另外Q对于大多数pȝQ会在这块内存空间中的首地址处记录本ơ分配的大小Q这P代码中的delete语句才能正确的释放本内存I间。另外,׃扑ֈ的堆l点的大不一定正好等于申L大小Q系l会自动的将多余的那部分重新攑օI闲链表中?
3.3甌大小的限?
栈:在Windows?栈是向低地址扩展的数据结构,是一块连l的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是pȝ预先规定好的Q在 WINDOWS下,栈的大小?MQ也有的说是1MQM是一个编译时q定的常数Q,如果甌的空间超q栈的剩余空间时Q将提示overflow。因此,能从栈获得的I间较小?
堆:堆是向高地址扩展的数据结构,是不q箋的内存区域。这是由于系l是用链表来存储的空闲内存地址的,自然是不q箋的,而链表的遍历方向是由低地址向高地址。堆的大受限于计算机系l中有效的虚拟内存。由此可见,堆获得的I间比较灉|Q也比较大?
3.4甌效率的比较:
栈由pȝ自动分配Q速度较快。但E序员是无法控制的?
堆是由new分配的内存,一般速度比较慢,而且Ҏ产生内存片,不过用v来最方便.
另外Q在WINDOWS下,最好的方式是用VirtualAlloc分配内存Q他不是在堆Q也不是在栈是直接在q程的地址I间中保留一快内存,虽然用v来最不方ѝ但是速度快,也最灉|
3.5堆和栈中的存储内?
栈: 在函数调用时Q第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句Q的地址Q然后是函数的各个参敎ͼ在大多数的C~译器中Q参数是由右往左入栈的Q然后是函数中的局部变量。注意静态变量是不入栈的?
当本ơ函数调用结束后Q局部变量先出栈Q然后是参数Q最后栈指针指向最开始存的地址Q也是dC的下一条指令,E序p点l运行?
堆:一般是在堆的头部用一个字节存攑֠的大。堆中的具体内容有程序员安排?
3.6存取效率的比?
char s1[] = "aaaaaaaaaaaaaaa";
char *s2 = "bbbbbbbbbbbbbbbbb";
aaaaaaaaaaa是在q行时刻赋值的Q?
而bbbbbbbbbbb是在~译时就定的;
但是Q在以后的存取中Q在栈上的数l比指针所指向的字W串(例如?快?
比如Q?
void main()
{
char a = 1;
char c[] = "1234567890";
char *p ="1234567890";
a = c[1];
a = p[1];
return;
}
对应的汇~代?10: a = c[1];
00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh]
0040106A 88 4D FC mov byte ptr [ebp-4],cl
11: a = p[1];
0040106D 8B 55 EC mov edx,dword ptr [ebp-14h]
00401070 8A 42 01 mov al,byte ptr [edx+1]
00401073 88 45 FC mov byte ptr [ebp-4],al
W一U在d时直接就把字W串中的元素d寄存器cl中,而第二种则要先把指针D到edx中,在根据edxd字符Q显然慢了?
3.7结Q?
堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜Q发出申P、付钱、和吃(使用Q,吃饱了就赎ͼ不必理会切菜、洗菜等准备工作和洗、刷锅等扫尾工作Q他的好处是快捷Q但是自由度?
使用堆就象是自己动手做喜Ƣ吃的菜_比较ȝQ但是比较符合自q口味Q而且自由度大?
堆和栈的区别主要分:
操作pȝ斚w的堆和栈Q如上面说的那些Q不多说了?
q有是数据l构斚w的堆和栈Q这些都是不同的概念。这里的堆实际上指的是Q满_性质的)优先队列的一U数据结构,W?个元素有最高的优先权;栈实际上是满先进后出的性质的数学或数据l构?
虽然堆栈Q堆栈的说法是连h叫,但是他们q是有很大区别的Q连着叫只是由于历史的原因?br />
url: http://www.shnenglu.com/ace
用例视图:对系l功能性需求对模,描述pȝ的行为,揭示pȝ“是什么?/p>
Customers, who need to be sure that the system that is getting built is the one that they want.
客户Q他们需要确定即构建的pȝ是他们需要的pȝ?/p>
Managers, who need to have an overall understanding of what the system will do in order to effectively plan and monitor the project.
l理Q他们需要对着手的pȝ有一个全局的了解,以便于对目有效的计划和监控?/p>
Analysts, who need to describe and document what the system is going to do.
分析员,他们需要对要着手的pȝq行描述和文档化?/p>
Developers, who need to understand what the system needs to do in order to develop it.
开发h员,他们需要理解系l以便于开发它?/p>
TesterQ?who need to know what the system is supposed to do so that they can verify that is does it.
试人员Q他们需要知道期望系l实现的功能Q以便于它们验证pȝ是执行这些功能?/p>
Technical writers,who need to know what the system is supposed to so that they can describe it.
支持文档撰写者,他们需求要知道期望的系l以例描q它?br />
User-experience designers, who need to understand the users' goals and how the will use the system to achieve these goals.
用户体验设计人员Q他们需要理解用L目标和他们将怎样使用pȝ辑ֈ他们的目标?/p>
在您l护安全cd和避免集成电路般函数?你可以用C++的强大的力量q行消息传递?/p>
Anthony是Just Software Solution有限公司的一位Y件开发者和执行理者。可以通过anthony@justsoftwaresolutions.co.uk与之联系?/p>
使用通用的消息传递方式传递数据在C++E序中很普遍。这U技术经常用于在U程间以及从/到GUIlg间传递数据。但是消息传递仍然很隑֮现得良好Q这是因为在常见的消息传递方式中Q暴露出了过多的藕合、缺类型安全和集成电\般的消息处理函数?/p>
在本文中Q我提出了一U技术,q种技术利用C++的强大力量来避免上述~陷——在消息传递中避免不适当的藕合,l护cd安全Q以及消除集成电路般的消息处理函? The only translation units that need to known the details of a message are those containning the source and handler functions for that specific message type.) 需要{换的单元Q即需要知道的消息详细内容是包含了特定消息的类型的源代码和处理函数?/p>
大概应用得最为广泛的消息传递技术是使用一个带有特D成员来表示消息cd的结构体Q该消息cd是消息的标识。这U方式被q泛应用归咎于用了ZC的APIQ比如X11和Microsoft Windows。在q种Ҏ中,消息l构体中要么有一个通用的字体用于区别不同消息的意义Q这个字D可被所有消息重用,或者它是更大结构的W一个成员,它的cdq型代码来定。Windows API使用前面的技术,而X11使用后面的方法。无论用哪种方式Q处理消息的代码都须查类型编码,用以军_怎么处理该消息?/p>
q些技术的问题?~Zcd安全Q集成电路般的处理函敎ͼ需要管理类型编码来保消息唯一性的适当层次。特别的Q缺乏类型安全意味着使用之前Q用代码必L消息数据转换成适当的类型。这一步是极易出错的,其在当复制和粘贴代码时(q种非常的手D常发生在ؓ处理怼消息~写代码的时?Q编译器不会在这U错误给ZQ何警告?/p>
~Zcd安全q有一个额外的问题——即它不可能单有效的通过消息pȝ传递资源或变长的数据, q是因ؓ消息的发送方L不能知道何时Q或是否Q该消息已被处理q了?/p>
在这部分Q集成电路般的消息处理函数是必须用于定消息cd的物,通过已接收的消息来消息类型,然后得到如何处理它的方式。这U处理函数往往实现Z个很大的switch语句或是一串if eles if。一些框Ӟ如MFCQ提供一些宏来减pU问题的影响Q它q不能完全消除这个问题?/p>
最后的问题是管理类型代码。它必须要求接收消息代码清楚地知道是哪一个消息,以便于正的处理它。所以,cd代码需要在处理它的相关代码中确保唯一性。比如,在Windows API中,指定范围的消息类型在不同的应用程序中代表不同的意义,q且Q在同一个应qE序中,其它范围的消息类型在不同H口或GUIlg中代表不同的意义?通常,需要所有类型代码的列表Q该列表要求在给定的范围中保持唯一Q以便于查它们的唯一性。列表常常是以头文g的Ş式给出,头文件中定义了类型代码,包含在需要知道消息类型的所有地斏V这U方式容易导致应用程序不同部分之间的藕合,而这些部分之间却没有M关系。由于这U过度的藕,单的变更Dq多的重新编译?/p>
面向对象技?br />
对象技术的一个常见特征是所有相x息类z自一个通用的基cR该特征用编译器能认识的真实cd代替了显式的cd代码。不仅如此,它还有了一个重要的Q超C风格技术的优点——类型安全。它提供的通用基类的析构函数是虚函敎ͼ所以派生的消息c能自由地管理资源,如变长的数据Q这些数据可以在析构函数中释放。仅有的需求是接受消息的代码能正确地销毁消息对象,无论它们是否被处理?/p>
理cd代码现在被替换ؓ理cR这是一个更加简单的dQ由于可能的消息名字的范围是没有限制的,可能存在名字冲突Q但q一点可以通过名字I间来解冟?/p>
最单的OOP技术就是用dynamic_cast查实际的消息cd代替查消息编码。然而,q依焉临着集成电\般地消息处理方式——现在通过包括dynamic_cast的比较链也优于通过cd~码字段比较链。如列表1:
[列表1]
一般而言Q由于仅仅是消息的源代码和接受消息的源代码需求知道相关的消息Q所以依赖得到降低。然后,集成电\般地处理函数现在需要知道消息的有关l节Q所以dynamic_cast需要消息的完整定义——如果分z另外的函数处理实际的消息QC风格技术的处理函数不需求知道消息的l节?/p>
(Direct testing of a class's type using dynamic_cast is generally indicative of a design problem;)cȝcd用dynamic_cast的直试一般可表示计问?然而,单地把虚函数攑֜消息cM起不CQ何作用——它把消息处理与消息缠l在一Pq个消息使在W一个地方发送消息的目的p|?/p>
双重分派的关键点是,在消息类中的虚函数带有一个作为参数的处理器,然后在处理器上把自已作ؓ参数传递传递给另一个函数ƈ完成调用。因里的W二ơ到处理器的回调已经在实际的zcM完成Q所以真实的消息cd已经知道Q在处理器上能调用适当的函敎ͼ无论q个函数是通过重蝲的方式实现还是另外独立命名的函数来实?列表2)?/p>
[列表2]
依赖于重载的方式来区别不同的消息有利于大多数q——现在在每个消息cM虚函数的实现方式是相同的Q如果需要,可以通过宏来一致地包装Q或通过从一个消息到另一个消息中直接复制Q不会有出错的机会?/p>
双重分派存在一个缺点——高度藕合。由于通过重蝲方式在处理器cM的选择处理函数Q在消息cM虚函数的实现需要知道处理器cȝ定义的全部,因此必须注意到在pȝ中每个其它的cȝ名字。不光这些,如果要支持不同的处理器类Q处理函数必d通用的处理器的基cM声明函数Q所以每个处理器cddpȝ中注意到所有的消息cd(列表3)。增加或删除一个消息类型会引v应用E序大部分代码重新编译?/p>
[列表3]
动态双重分z?br />
QIt was against this backdrop that I developed the technique I call "Dynamic Double Dispatch."Q我开发了一U技术,我称其ؓ“动态双重分z䏀,q种技术用于解决上q问题。尽有基本的双重分z技术,但选择的消息处理函C用的是在~译阶段定的重载技?管发现在正的消息处理器类中的实现是用虚函数机制),而动态双重分z是在运行时查在处理器上适当的处理函数的。结论是动态双重分z消除了双重分派的依赖问题。消息类型不在需要注意到其它的消息类型,q且处理器类仅需要注意到它的它要处理的消息?/p>
动态检查的关键ҎQ每一个消息类型有一个独立的基类——处理器cM适当的,设计为处理消息的基类z。然后在每个消息cM的分zև数能用dynamic_cast来检查从正派基类z的处理器c,因而实C正确的处理函数?列表4)
[列表4]
(Of course, having a completely separate handler base class for each message type would add excessive complication, as the dispatch function for each message type would now be specific to that message type, and the base classes would have to be written separately, despite being fundamentally the same, except for the message type they referenced.)
诚然Qؓ每个消息cd分别~写的处理器基类增加过多的复杂性,同样圎ͼ每个消息cd各自的分zև数现在需要特别指定,基类也需求分别编?然后除了它们引用的消息类型外基础是相同的。消除这U重复的关键是基类成ؓ模板Q用消息cd作ؓ模板参数——分zև数引用到模板的实现好于指定类型;L列表5?/p>
[列表5]
Z化原因,在消息类中的分派函数几乎相同Q但也不是完全相同——它们必L的指定属于它们的指定消息类Q以便于转换为适当的处理器基类。像软g中许多事情一Pq个问题可以增加一个额外的层来解决——分zև数可以委托给单个模板函数Q这个模板函C用模板参数类型来定消息cd和把处理器{换到适当的类型上?列表6)
[列表6]
通过q一步抽象在消息对象中分zև数的不同之处,我们把工作集中到一个地方——模板函数的定义Q它提供了ؓ修改行ؓ的单一炏V在消息cM剩下的分zև数都是相同的Q这以把它们简化到隐藏l节的宏中或在消息类之间中逐字复制?/p>
未处理的消息
q今为止Q我们展C的 dynamicDispach模板函数的代码假定处理的cL从适当的SpecificMessageHandler是派生的Q如是不是这P dynamic_cast抛出std::bad_cast异常。有时这p够了Q但是有的时候,有更适当的行为——也许更好的做法是抛弃消息,q不能被接受消息的代理处理或调用catch-all处理器。D例来_dynamicDispatch 函数能被调整Q用Z指针的{换代替基于引用的转换Q所以结果值可以与NULLq行试?/p>
~点(Trade-Off)在哪里?
有如此多的优点,一定存在它的缺点,那它的缺点在哪里呢?在这里,有两个缺炏V第一个是Q额外的动态{换,两个虚函数调用会影响性能。如果性能上是一个问题,q就是一个疑问,但是Q在很多情况下,花销在这里的额外的时间是不值得x的。可以用相应的工具来签定到底哪里才是真正的性能瓉所在?/p>
W二个缺Ҏ:需要ؓ每个消息处理从指定的基类z消息处理器。因为处理新的消息类型需要修改两个地方——适当的基cd表入口和处理函数Q所以这可能成ؓ错误的来源,遗失处理函数Ҏ被发玎ͼ因ؓq是全局点,但是遗失基类在代码运行时只生不易查觉的~陷。因为没有处理函数的时候仅仅是不调用它。这些错误在单元试的时候是很容易被抓出来的Q所以所实话Q这些不便之处都成不了大问题?/p>
From: Brian Sun @ 爬树的泡[http://www.blogjava.net/briansun]
{关键字}
试驱动开?Test Driven Development/TDD
试用例/TestCase/TC
设计/Design
重构/Refactoring
{TDD的目标}
Clean Code That Works
q句话的含义是,事实上我们只做两件事情:让代码奏效(WorkQ和让代码洁净QCleanQ,前者是把事情做对,后者是把事情做好。想想看Q其实我们^时所做的所有工作,除去无用的工作和错误的工作以外,真正正确的工作,q且是真正有意义的工作,其实也就只有两大c:增加功能和提升设计,而TDD 正是在这个原则上产生的。如果您的工作ƈ非我们想象的q样Q(q意味着您还存在W三cL有意义的工作,或者您所要做的根本和我们在说的是两回事)Q那么这告诉我们您ƈ不需要TDDQ或者不适用TDD。而如果我们偶然猜对(q对于我来说是偶Ӟ而对于Kent Beck和Martin Fowlerq样的大师来说则是辛勤工作的成果Q,那么恭喜您,TDD有可能成为您显著提升工作效率的一件法宝。请不要信疑Q若卌,因ؓM一Ҏ的技术——只要是从根本上改变人的行ؓ方式的技术——就必然使得怿它的来越怿Q不信的来越不信。这好比学游泳Q唯一能学会游泳的途径是亲自下去游,除此之外别无他法。这也好比成功学Q即使把卡耐基或希博士的书倒背如流也不能拥有积极的心态,可当你以U极的心态去成就了一番事业之后,你就再也M开它了。相信我QTDD也是q样Q想试用TDD的h们,请遵循下面的步骤Q?/p>
~写TestCase --> 实现TestCase --> 重构 Q确定范围和目标Q?/td> Q增加功能) Q提升设计)
[友情提示Q敏捷徏模中的一个相当重要的实践被称为:Prove it With CodeQ这U想法和TDD不谋而合。]
{TDD的优点}
『充满吸引力的优炏V?/b>
『不显而易见的优点?/b>
『有争议的优炏V?/b>
~写TestCase --> 实现TestCase --> 重构 Q不可运行) Q可q行Q?/td> Q重构)
步骤 | 制品 |
Q?Q快速新增一个测试用?/td> | 新的TestCase |
Q?Q编译所有代码,刚刚写的那个试很可能编译不通过 | 原始的TODO List |
Q?Q做可能少的改动,让编译通过 | Interface |
Q?Q运行所有的试Q发现最新的试不能~译通过 | Q?Red Bar) |
Q?Q做可能少的改动,让测试通过 | Implementation |
Q?Q运行所有的试Q保证每个都能通过 | Q?Green Bar) |
Q?Q重构代码,以消除重复设?/td> | Clean Code That Works |
{FAQ}
[什么时候重构?]
如果您在软g公司工作Q就意味着您成天都会和想通过重构改善代码质量的想法打交道Q不仅您如此Q您的大部分同事也都如此。可是,I竟什么时候该重构Q什么情况下应该重构呢?我相信您和您的同事可能有很多不同的看法,最常见的答案是“该重构旉构”,“写不下ȝ时候重构”,和“下一ơP代开始之前重构”,或者干脆就是“最q没旉Q就不重构了Q下ơ有旉的时候重构吧”。正如您已经预见到我惌的——这些想法都是对重构的误解。重构不是一U构Y件的工具Q不是一U设计Y件的模式Q也不是一个Y件开发过E中的环节,正确理解重构的h应该把重构看成一U书写代码的方式Q或习惯Q重构时时刻L可能发生。在TDD中,除去~写试用例和实现测试用例之外的所有工作都是重构,所以,没有重构M设计都不能实现。至于什么时候重构嘛Q还要分开看,有三句话是我的经验:实现试用例旉构代码,完成某个Ҏ时重构设计Q品的重构完成后还要记得重构一下测试用例哦?/p>
[什么时候设计?]
q个问题比前面一个要隑֛{的多,实话实说Q本人在依照TDD开发Y件的时候也常常被这个问题困扎ͼL觉得有些问题应该在写试用例之前定下来,而有些问题应该在新增一个一个测试用例的q程中自然出玎ͼ水到渠成。所以,我的是,设计的时机应该由开发者自己把握,不要受到TDD方式的限Ӟ但是Q不需要事先确定的事一定不能事先确定,免得捆住了自q手脚?/p>
[什么时候增加新的TestCaseQ]
没事做的时候。通常我们认ؓQ如果你要增加一个新的功能,那么先写一个不能通过?TestCaseQ如果你发现了一个bugQ那么先写一个不能通过的TestCaseQ如果你现在什么都没有Q从0开始,请先写一个不能通过?TestCase。所有的工作都是从一个TestCase开始。此外,q要注意的是Q一些大师要求我们每ơ只允许有一个TestCase亮红灯,在这?TestCase没有Green之前不可以写别的TestCaseQ这U要求可以适当考虑Q但即有多个TestCase亮红灯也不要紧,q未q反TDD 的主要精?/p>
[TestCase该怎么写?]
试用例的编写实际上是两个q程Q用尚不存在的代码和定义这些代码的执行l果。所以一?TestCase也就应该包括两个部分——场景和断言。第一ơ写TestCase的h会有很大的不适应的感觉,因ؓ你之前所写的所有东襉K是在解决问题Q现在要你提出问题确实不大习惯,不过不用担心Q你正在做正的事情Q而这个世界上最隄事情也不在于如何解决问题Q而在于ask the right questionQ?/p>
[TDD能帮助我消除Bug吗?]
{:不能Q千万不要把“测试”和“除虫”Z谈!“除虫”是指程序员通过自己的努力来减少bug的数量(消除bugq样的字眼我们还是不要讲为好^_^Q,而“测试”是指程序员书写产品以外的一D代码来保产品能有效工作。虽然TDD所~写的测试用例在一定程度上为寻找bug提供了依据,但事实上Q按照TDD的方式进行的软g开发是不可能通过TDD再找到bug的(x我们前面说的“完工时完工”)Q你惛_Q当我们的代码完成的时候,所有的试用例都亮了绿灯,q时隐藏在代码中的bug一个都不会露出马脚来?/p>
但是Q如果要问“测试”和“除虫”之间有什么联p,我相信还是有很多话可以讲的,比如TDD事实上减了bug的数量,把查找bug战役的关注点从全U战场提升到代码战场以上。还有,bug的最可怕之处不在于隐藏之深Q而在于满天遍野。如果你发现了一个用户很不容易才能发现的bugQ那么不一定对工作做出了什么杰A献,但是如果你发CD代码中Qbug的密度或LE度q高Q那么恭喜你Q你应该抛弃q写这D代码了。TDD避免了这U情况,所以将Lbug的工作降低到了一个新的低度?/p>
[我该Z个Feature~写TestCaseq是Z个类~写TestCaseQ]
初学者常问的问题。虽然我们从TDD 的说明书上看到应该ؓ一个特性编写相应的TestCaseQ但Z么著名的TDD大师所写的TestCase都是和类/Ҏ一一对应的呢Qؓ了解释这个问题,我和我的同事们都做了很多试验Q最后我们得C一个结论,虽然我不知道是否正确Q但是如果您没有{案Q可以姑且相信我们?/p>
我们的研I结果表明,通常在一个特性的开发开始时Q我们针对特性编写测试用例,如果您发现这个特性无法用TestCase表达Q那么请这个特性细分,直至您可以ؓ手上的特性写出TestCase为止。从q里开始是最安全的,它不会导致Q何设计上重大的失误。但是,随着您不断的重构代码Q不断的重构 TestCaseQ不断的依据TDD的思想做下去,最后当产品伴随试用例集一起发布的时候,您就会不l意的发现经q重构以后的试用例很可能是和品中的类/Ҏ一一对应的?/p>
[什么时候应该将全部试都运行一遍?]
Good QuestionQ大师们要求我们每次重构之后都要完整的运行一遍测试用例。这个要求可以理解,因ؓ重构很可能会改变整个代码的结构或设计Q从而导致不可预见的后果Q但是如果我正在开发的是一个ERP怎么办?q行一遍完整的试用例可能花Ҏ个小Ӟ况且现在很多重构都是由工具做到的Q这个要求的可行性和前提条g都有所动摇。所以我认ؓ原则上你可以挑几个你觉得可能受到本次重构影响的TestCase去runQ但是如果运行整个测试包只要p数秒的时_那么不介意你按大师的要求d?/p>
[什么时候改q一个TestCaseQ]
增加的测试用例或重构以后的代码导致了原来的TestCase的失M效果Q变得无意义Q甚臛_能导致错误的l果Q这时是改进TestCase的最好时机。但是有时你会发玎ͼq样做仅仅导致了原来的TestCase在设计上是臃肿的Q或者是冗余的,q都不要紧,只要它没有失效,你仍然不用去改进它。记住,TestCase不是你的产品Q它不要好看Q也不要怎么太科学,甚至没有性能要求Q它只要能完成它的命就可以了——这也证明了我们后面所说的“用Ctrl-C/Ctrl-V~写试用例”的可行性?/p>
但是Q美国h的想法其实跟我们q是不太一P拿托巴赞的MindMap来说吧,其实画MindMap只是Z表现自己的思\Q或记忆某些重要的事情,但托却大家把MindMapL一件艺术品Q甚臌有很多艺术家把自q的抽象派MindMap拿出来帮助托做宣传。同P大师们也要求我们把TestCase写的跟代码一栯量精良,可我惌的是Q现在国内有几个公司能把产品的代码写的精良?Q还是一步一步慢慢来吧?/p>
[Z么原来通过的测试用例现在不能通过了?]
q是一个警报,Red AlertQ它可能表达了两层意思——都不是什么好意思—?Q你刚刚q行的重构可能失败了Q或存在一些错误未被发玎ͼ臛_重构的结果和原来的代码不{h了?Q你刚刚增加的TestCase所表达的意思跟前面已经有的TestCase相冲H,也就是说Q新增的功能q背了已有的设计Q这U情况大部分可能是之前的设计错了。但无论哪错了,无论是那层意思,x到这个问题的Ҏ都比TDD的正常工作要难?/p>
[我怎么知道那里该有一个方法还是该有一个类Q]
q个问题也是常常出现在我的脑中Q无Z是第一ơ接触TDD或者已l成?TDD专家Q这个问题都会缠l着你不放。不q问题的{案可以参考前面的“什么时候设计”一节,{案不是唯一的。其实多数时候你不必考虑未来Q今天只做今天的事,只要有重构工P从方法到cd从类到方法都很容易?/p>
[我要写一个TestCaseQ可是不知道从哪里开始?]
从最重要的事开始,what matters mostQ从脚下开始,从手头上的工作开始,从眼前的事开始。从一个没有UI的核心特性开始,从算法开始,或者从最有可能耽误旉的模块开始,从一个最严重的bug开始。这是TDDM者和鼠目寸光者的一个共同点Q不同点是前者早已成竹在胸?/p>
[Z么我的测试L看v来有Ҏ蠢?]
哦?是吗Q来Q握个手Q我的也是!不必担心q一点,事实上,大师们给的例子也相当愚蠢Q比如一个极端的例子是要写一个两个int变量相加的方法,大师先断a2+3=5Q再断言5+5=10Q难道这些代码不是很愚蠢吗?其实q只是一个极端的例子Q当你初ơ接触TDDӞ写这L代码没什么不好,以后当你熟练时就会发现这样写没必要了Q要CQ谦虚是通往TDD的必l之路!从经典开发方法{向TDD像从面向过E{向面向对象一样困难,你可能什么都懂,但你写出来的cL有一个纯OO的!我的同事q告诉我真正的太极拳Q其速度是很快的Q不比Q何一个快拌慢,但是初学者(通常是指学习太极拳的?0q_太不Ҏ把每个姿劉K做对Q所以只能慢慢来?/p>
[什么场合不适用TDDQ]
问的好,实有很多场合不适合使用TDD。比如对软g质量要求极高的军事或U研产品——神州六P人命兛_的Y件——医疗设备,{等Q再比如设计很重要必L前做好的软gQ这些都不适合TDDQ但是不适合TDD不代表不能写TestCaseQ只是作用不同,C不同|了?/p>
{Best Practise}
[微笑面对~译错误]
学生时代最x的是~译错误Q编译错误可能会被老师视ؓ上课不认真听评证据Q或者同学间怺嘲笑的砝码。甚至离开学校很多q的老程序员依然x它像x迟CP潜意识里g~译错误极有可能和工资挂钩(或者和智商挂钩Q反正都不是什么好事)。其实,只要提交到版本管理的代码没有~译错误可以了Q不要担心自己手上的代码的编译错误,通常Q编译错误都集中在下面三个方面:
Q?Q你的代码存在低U错?br />Q?Q由于某些Interface的实现尚不存在,所以被试代码无法~译
Q?Q由于某些代码尚不存在,所以测试代码无法编?br />h意第二点与第三点完全不同Q前者表明设计已存在Q而实C存在D的编译错误;后者则指仅有TestCase而其它什么都没有的情况,设计和实现都不存在,没有Interface也没有Implementation?/p>
另外Q编译器q有一个优点,那就是以最敏捷的n手告诉你Q你的代码中有那些错误。当然如果你拥有Eclipseq样可以及时提示~译错误的IDEQ就不需要这L功能了?/p>
[重视你的计划清单]
在非TDD的情况下Q尤其是传统的瀑布模型的情况下Q程序员不会不知道该做什么,事实上,L有设计或者别的什么制品在引导E序员开发。但是在TDD的情况下Q这U优势没有了Q所以一个计划清单对你来说十分重要,因ؓ你必自己发现该做什么。不同性格的h对于q一点会有不同的反应Q我怿qx做事没什么计划要依靠别h安排的hQ所谓将才)可能略有不适应Q不q不要紧QTasks和CalendarQ又U效率手册)早已成ؓC上班族的必备工具了;而^时工作生zd很有计划性的人,比如?)Q就会更喜欢q种自己可以掌控Plan的方式了?/p>
[废黜每日代码质量查]
如果我没有记错的话,PSP对于个h代码查的要求是蛮严格的,而同h在针对个人的问题上, TDD却徏议你废黜每日代码质量查,别v疑心Q因ZL在做TestCase要求你做的事情,q且L有办法(自动的)查代码有没有做到q些事情 ——红灯停l灯行,所以每日代码检查的旉可能被节省,对于一个严格的PSP实践者来_q个成本q是很可观的Q?/p>
此外Q对于每日代码质量检查的另一个好处,是帮助你认识自q代码Q全面的从宏观、微观、各个角度审视自q成果Q现在,当你依照TDD做事Ӟq个优点也不需要了Q还记得前面说的TDD的第二个优点吗,因ؓ你已l全面的使用了一遍你的代码,q完全可以达到目的?/p>
但是Q问题往往也ƈ不那么简单,现在有没有h能告诉我Q我如何全面审视我所写的试用例呢?别忘了,它们也是以代码的形式存在的哦。呵呵,但愿q个问题没有把你吓到Q因为我怿到目前ؓ止,它还不是瓉问题Q况且在~写产品代码的时候你q是会自ȝ发现很多试代码上的没考虑到的地方Q可以就此修改一下。道理就是如此,世界上没有Q何方法能代替你思考的q程Q所以也没有MҎ能阻止你犯错误,TDD仅能让你更容易发现这些错误而已?/p>
[如果无法完成一个大的测试,׃最的开始]
如果我无法开始怎么办,教科书上有个很好的例子:我要写一个电影列表的c,我不知道如何下手Q如何写试用例Q不要紧Q首先想象静态的l果Q如果我的电影列表刚刚徏立呢Q那么它应该是空的,OKQ就写这个断a吧,断言一个刚刚初始化的电影列表是I的。这不是愚蠢Q这是细节,奥运会五全能的金牌得主玛丽莲·金是这栯的:“成功h士的共同点在于……如果目标不够清晎ͼ他们会首先做通往成功道\上的每一个细步骤……”?/p>
[试~写自己的xUnit]
Kent Beck大家每当接触一个新的语a或开发^台的时候,p己写q个语言或^台的xUnitQ其实几乎所有常用的语言和^台都已经有了自己?xUnitQ而且都是大同异Q但是ؓ什么大师给Zq样的徏议呢。其实Kent Beck的意思是说通过q样的方式你可以很快的了解这个语a或^台的Ҏ,而且xUnit实很简单,只要知道原理很快p写出来。这对于那些喜欢自己写底层代码的人,或者喜Ƣ控制力的h而言是个好消息?/p>
[善于使用Ctrl-C/Ctrl-V来编写TestCase]
不必担心TestCase会有代码冗余的问题,让它冗余好了?/p>
[永远都是功能FirstQ改q可以稍后进行]
上面q个标题q可以改成另外一句话Q避免过渡设计!
[淘汰陈旧的用例]
舍不得孩子套不着狹{不要可惜陈旧的用例Q因为它们可能从概念上已l是错误的了Q或仅仅会得出错误的l果Q或者在某次重构之后失去了意义。当然也不一定非要删除它们,从TestSuite中除去(JUnitQ或加上IgnoredQNUnitQ标{也是一个好办法?/p>
[用TestCase做试验]
如果你在开始某个特性或产品的开发之前对某个领域不太熟悉或一无所知,或者对自己在该领域里的能力一无所知,那么你一定会选择做试验,在有单元试作工L情况下,你用TestCase做试验,q看h像你在写一个验证功能是否实现的 TestCase一P而事实上也一P只不q你所验证的不是代码本w,而是q些代码所依赖的环境?/p>
[TestCase之间应该量独立]
保证单独q行一个TestCase是有意义的?/p>
[不仅试必须要通过的代码,q要试必须不能通过的代码]
q是一个小技巧,也是不同于设计思\的东ѝ像界的值或者ؕ码,或者类型不W的变量Q这些输入都可能会导致某个异常的抛出Q或者导致一个标C“illegal parameters”的q回|q两U情况你都应该测试。当然我们无法枚举所有错误的输入或外部环境,q就像我们无法枚举所有正的输入和外部环境一P只要TestCase能说明问题就可以了?/p>
[~写代码的第一步,是在TestCase中用Ctrl-C]
q是一个高U技巧,呃,是的Q我是这个意思,我不是说q个技巧难以掌握,而是说这个技巧当且仅当你已经是一个TDD高手Ӟ你才能体会到它的力。多ơ用TDD的h都有q样的体会,既然我的TestCase已经写的很好了,很能说明问题Qؓ什么我的代码不能从TestCase拯一些东西来呢。当Ӟq要求你的TestCase已经h很好的表达能力,比如断言f (5)=125的方式显然没有断af(5)=5^(5-2)表达更多的内宏V?/p>
[试用例包应该尽量设计成可以自动q行的]
如果产品是需要交付源代码的,那我们应该允许用户对代码q行修改或扩充后在自q环境下run整个试用例包。既焉常情况下的产品是可以自动运行的Q那Z么同样作Z付用L制品Q测试用例包׃是自动运行的呢?即产品不需要交付源代码Q测试用例包也应该设计成可以自动q行的,qؓ试部门或下一版本的开发h员提供了极大的便利?/p>
[只亮一盏红灯]
大师的徏议,前面已经提到了,仅仅是徏议?/p>
[用TestCase描述你发现的bug]
如果你在另一个部门的同事使用了你的代码,q且Q他发现了一个bugQ你猜他会怎么做?他会立即走到你的工位边上Q大声斥责说Q“你有bugQ”吗Q如果他胆敢q样对你Q对不vQ你一定要冷静下来Q不要当面回骂他Q相反你可以微微一W,然后心^气和的对他说Q“哦Q是吗?那么好吧Q给我一个TestCase证明一下。”现在局势已l倒向你这一边了Q如果他q没有准备好回答你这致命的一击,我猜他会感到非常愧Qƈ在内心责怪自己太莽撞。事实上Q如果他的TestCase没有q多的要求你的代码(而是按你们事前的契约Q,q且亮了U灯Q那么就可以定是你的bugQ反之,Ҏ则无理了。用TestCase描述bug的另一个好处是Q不会因Z后的修改而再ơ暴露这个bugQ它已经成ؓ你发布每一个版本之前所必须查的内容了?/p>
{关于单元试}
单元试的目标是
Keep the bar green to keep the code clean
q句话的含义是,事实上我们只做两件事情:让代码奏效(Keep the bar greenQ和让代码洁净QKeep the code cleanQ,前者是把事情做对,后者是把事情做好,两者既是TDD中的两顶帽子Q又是xUnit架构中的因果关系?/p>
单元试作ؓ软g试的一个类别,q是xUnit架构创造的Q而是很早有了。但是xUnit架构使得单元试变得直接、简单、高效和规范Q这也是单元试最q几q飞速发展成量一个开发工具和环境的主要指标之一的原因。正如Martin Fowler所_“Y件工E有史以来从没有如此众多的h大大收益于如此简单的代码Q”而且多数语言和^台的xUnit架构都是大同异Q有的仅是语a不同Q其中最有代表性的是JUnit和NUnitQ后者是前者的创新和扩展。一个单元测试框架xUnit应该Q?Q每个TestCase独立q行Q?Q每个TestCase可以独立和报告错误Q?Q易于在每次q行之前选择TestCase。下面是我枚丑և的xUnit框架的概念,q些概念构成了当前业界单元测试理论和工具的核心:
[试Ҏ/TestMethod]
试的最单位,直接表示Z码?/p>
[试用例/TestCase]
由多个测试方法组成,是一个完整的对象Q是很多TestRunner执行的最单位?/p>
[试容器/TestSuite]
由多个测试用例构成,意在把相同含义的试用例手动安排在一PTestSuite可以呈树状结构因而便于管理。在实现ӞTestSuite形式上往往也是一个TestCase或TestFixture?/p>
[断言/Assertion]
断言一般有三类Q分别是比较断言Q如assertEqualsQ,条g断言Q如isTrueQ,和断a工具Q如failQ?/p>
[试讑֤/TestFixture]
为每个测试用例安排一个SetUpҎ和一个TearDownҎQ前者用于在执行该测试用例或该用例中的每个测试方法前调用以初始化某些内容Q后者在执行该测试用例或该用例中的每个方法之后调用,通常用来消除试对系l所做的修改?/p>
[期望异常/Expected Exception]
期望该测试方法抛出某U指定的异常Q作Z个“断a”内容,同时也防止因为合情合理的异常而意外的l止了测试过E?/p>
[U类/Category]
为测试用例分c,实际使用时一般有TestSuite׃再用CategoryQ有Category׃再用TestSuite?/p>
[忽略/Ignored]
讑֮该测试用例或试Ҏ被忽略,也就是不执行的意思。有些被抛弃的TestCase不愿删除Q可以定为Ignored?/p>
[试执行?TestRunner]
执行试的工P表示以何U方式执行测试,别误会,q可不是在代码中规定的,完全是与试内容无关的行为。比如文本方式,AWT方式Qswing方式Q或者Eclipse的一个视囄{?/p>
{实例QFibonacci数列}
下面的Sample展示TDDer是如何编写一个旨在生Fibonacci数列的方法?br />Q?Q首先写一个TCQ断afib(1) = 1;fib(2) = 1;q表C数列的第一个元素和W二个元素都??/p>
Q?Q上面这D代码不能编译通过QGreatQ——是的,我是说GreatQ当Ӟ如果你正在用的是Eclipse那你不需要编译,Eclipse 会告诉你不存在fibҎQ单击mark会问你要不要新徏一个fibҎQOhQ当ӞZ让上面那个TC能通过Q我们这样写Q?/p>
Q?Q现在那个TC亮了l灯QwowQ应该庆一下了。接下来要增加TC的难度了Q测W三个元素?/p>
不过q样写还不太好看Q不如这样写Q?/p>
Q?Q新增加的断aD了红灯,Z扭{q一局势我们这样修改fibҎQ其中部分代码是从上面的代码中Ctrl-C/Ctrl-V来的Q?/p>
Q?Q天哪,q真是个׃h写的代码Q是啊,不是吗?因ؓTC是产品的蓝本,产品只要恰好满TCok。所以事情发展到q个地步不是fibҎ的错Q而是TC的错Q于是TCq要q一步要求:
Q?Q上有政{下有对{?/p>
Q?Q好了,不玩了。现在已l不是贱不贱的问题了Q现在的问题是代码出C冗余Q所以我们要做的是——重构:
Q?Q好Q现在你已经fibҎ已经写完了吗Q错了,一个危险的错误Q你忘了错误的输入了。我们o0表示Fibonacci中没有这一V?/p>
then change the method fib to make the bar greanQ?/p>
Q?Q下班前最后一件事情,把TC也重构一下:
Q?0Q打完收工?/p>
{关于本文的写作}
在本文的写作q程中,作者也用到了TDD的思维Q事实上作者先构思要写一什么样的文章,然后写出q篇文章应该满的几个要求,包括功能的要求(要写些什么)和性能的要求(可读性如何)和质量的要求Q文字的要求Q,q些要求起初是一个也达不到的Q因为正文还一个字没有Q,在这U情况下作者的文章无法~译通过Qؓ了达到这些要求,作者不停的写啊写啊Q终于在花尽了两个月的心血之后完成了当初既定的所有要求(make the bar greenQ,随后作者整理了一下文章的l构Q重构)Q在满意的提交给了Blogpȝ之后Q作者穿上了一件绿色的汗衫Q趴在地上,学了两声青蛙叫。。。。。。。^_^
{后记QMartin Fowler在中国}
从本文正式完成到发表的几个小旉Q我偶然d了Martin Fowler先生北京访谈录,光提到了很多对试驱动开发的看法Q摘抄在此:
Martin FowlerQ当Ӟ值得׃半的旉来写单元试Q!因ؓ单元试能够使你更快的完成工作。无数次的实践已l证明这一炏V你的时间越是紧张,p要写单元试Q它看上LQ但实际上能够帮助你更快、更舒服地达到目的?br />Martin FowlerQ什么叫重要Q什么叫不重要?q是需要逐渐认识的,不是惛_然的。我为绝大多数的模块写单元测试,是有点烦人,但是当你意识到这工作的h值时Q你会欣然的?br />Martin FowlerQ对全世界的E序员我都是那么几条Q……第二,学习试驱动开发,q种新的Ҏ会改变你对于软g开发的看法。…?/font>
——《程序员》,2005q?月刊
{鸣谢}
fhawk
Dennis Chen
般若菩提
Kent Beck
Martin Fowler
c2.com
阅读W记Q积极主动,充满热情Q是q封信的核心。最q自׃l历了一些事情,在面临未来发展前景的分岔道\Q需要做出选择Ӟ明知道某一条具有更大的发展前景Q但是却׃未知的待遇问题放弃了选择它,q不积极主动,不充满热情,但是某些时候有很多的外在因素可以媄响决定?/strong>
李开复《给中国学生的第五封信》,l箋传授关于U极行动、把握自己命q的人生l验Q这是“一有关积极主动的信”?
“今天大多数优秀的企业对人才的期望是Q积极主动、充满热情、灵z自信的人”,学会“自q事,自己负责Q自p决”,“我不能Q别的Q何h也不能代替你走过那条路;你必自己去走。?/p>
一个h被击败,不是因ؓ外界环境的阻,而是取决于他对环境如何反应。“有勇气改变可以改变的事情,有胸怀接受不可改变的事情,有智慧来分L两者的不同。?/p>
“如果你想知道什么,p己到|上LQ不要急着去问别hQ如果你听到了什么,不要盲目信从Q应当自׃动去|上求证。?/p>
被动是弃权Q不做决定也是一U决定。下定决心,每一件小事都要表辑և自己的意见,q你不是很在乎。例如,自己军_在餐馆点什么菜Q自己决定自q衣着打扮Q周末时自己军_要去哪里玩,{等。设法让自己潜意识里的“我感觉Q我惌”体现出来,不要被动Q不要从众,避免盲目听从父母、老师、名人…?/p>
U极d的hL在言语中赋予自己军_的权利,他们喜欢说的话包括:“试试看有没有其他的可能性。”“也许我可以换个思\。”“我可以控制自己的情l。”“我可以惛_更有效的表达方式。”“我的感觉是……”“我选择……”“我要……”“我情愿……”“我打算……”“我军_……”等{。积极主动地抓住命运中你可以选择、可以改变、可以最大化你的影响力的部分?/p>
国人很喜欢试不同的工作,他们一生中q_要换四次工作。经常给自己讄一些极h战性、但l非遥不可及的目标?/p>
“等待的Ҏ有两U,一U是什么事也不做地I等Q另一U是一边等Q一Ҏ事情向前推动。”在机遇q没有来临时Q就应事事用心,事事力。一旦机遇到来,一定要全力以ʎQ把握机遇?/p>
在公叔RQ经常得到晋升机会的人,大多是能够积极推销和表达自q、有q取心的人。当他们q是公司的一名普通员工时Q只要和公司利益或者团队利益相关的事情Q他们就会不遗余力地发表自己的见解、A献自qdQ帮助公司制定和安排工作计划Q在完成本职工作后,他们总能协助其他人尽快完成工作;他们常常鼓励自己和同_提高整个队伍的士气;q些人L以事为本、以事ؓ先——他们都是最U极d的h?/p>
在h生的旅途中Q你是你自己惟一的司机,千万不要让别人驾驶你的生命之车。你要稳E_坐在司机的位|上Q决定自׃时要停、要倒R、要转弯、要加速、要刹R{等。只有积极主动的人才能在瞬息万变的竞争环境中赢得成功Q只有善于展Cq人才能在工作中获得真正的Z?/p>
“你们的旉有限Q所以不要浪Ҏ间在别h的生z里。不要被信条所??盲从信条是活在别人的生活里。不要让M人的意见Ҏ了你内在的心声。重要的Q拥有跟随内心和直觉的勇气。你的内心与直觉知道你真正想成ؓ什么样的h。Q何其他事物都是次要的。”——斯蒂夫 乔布?Q苹果公司总裁Q于2005q斯坦福大学毕业典礼?/p>
1、整理出一个大?0GQ最?GQ左右的分区Q用PQ8分两个区Q一个Swap1.2GQ一个ext2/ext3的格式,用于安装Linuxpȝ
2、下载ISO文gC个FAT32格式的分ZQ约?.57GB大小Q如D:\FC4\
3、下载:Grub For Dos Q放到C盘(我的WinXP安装在C盘)根目录下
4、编辑C:\boot.ini 文gQ加入一?br />C:\grldr="GRUB For Dos/Windows "
5、编辑C:\boot\grub\menu.lst 加入Q?
title Install-Fedora Core 4
kernel (hd0,0)/isolinux/vmlinuz
initrd (hd0,0)/isolinux/initrd.img
5、重新启动电脑,依次选择Q?GRUB For Dos/Windows > Install-Fedora Core 4Q进入安装程序,在安装过E中当进行到选择安装介质Ӟ选硬盘安装,扑ֈ自己ISO攄的位|,如dev/sdm2/Fc4
6、进入正式安装,在选择分区的时候,把ext2/ext3的分行挂载即可,其他按照提示操作Q挂载简单的操作是选中ext2/ext3的分区,然后选择下拉菜单中的"/"卛_Q?/p>
7、安装,Ҏ模块的加载的多少Q机器的q行速度Q时间由20分钟?个小时不{?/p>
8、安装好之后讄用户名和密码Q注意FC4的用户名是区分大写?/p>
9、安装好之后?用户名root+密码 登陆
10、打开应用E序下的TerminalQ运行如下命令,对系l进行升U?br />#rpm -import /usr/share/rhn/RPM-GPG-KEY-fedora
#yum update
大约10分钟左右Q会列出800多兆需要更新的E序包,q行更新卛_
11、美化一下中文字?br />下蝲字体Q?a >http://www.bitman.cn/Linux/bkai00mp.ttf
q入文g夹: #cd /usr/share/fonts/chinese/TrueTypa
删除下面所有的字体Q然后把bkai00mp.ttf攄到如上目录即?/p>
于学计算机或者从事这斚w工作的朋?
1、首先,不论你是不是计算Z业的朋友Q相信一句话。“想成功不努力是不行的”,只要你努力,无论你是不是学计机的都会获得成功的。如果你不努力,无论你是不是学计机的,都很难的?br />2、无论学什么专业。一定要先做人,再做事,如果你做人有问题Q无Z做什么都是失败的。要提高自己的素质,需要^时有意识的积累。多交比较上q的朋友。别滥交朋友,比如多结交小w之类的朋?)
3、如果你以后的工作意x软g公司Q那么你必须要懂得至一门开发语a。即使你的志向比较高你也必须从开发开始,否则同事是瞧不v你的。而且较ؓ熟练的用,如果有相关的目l验最为合适。程序开发是很辛苦的工作,在你q没准备好这个方向之?一定要惛_q个是不是你惌?对于itq行?你必d备好随时学习新的东西,打算学一两个工具可以一生的x千万别想.如果你是本科?包括以下),q是你必要准备?
偶曾l用q的工具(旉序):aspQ比较熟l)QpbQ用q?个月,现在全忘讎ͼ,delphiQ用q一D|?现在忘的差不多),exchangeQ用q?个月,现在全忘讎ͼ,Lotus notes(用过2个月Q开发过一个论坛,也忘记的差不?QjavaQ主要是写jsp用。很用来写javaQ,primetonQ构件开发工P一直在用,比较熟练Q,plsqlQoracle客户端工Pl常用,比较熟练Q?br />逐步告别E序开发生zR?br />4、如果你是研I生Q包括比较有l验的从业h员)Q你的目标不应该是程序开发h员,臛_是设计h员。这个时候你有两个方向,一个是目理Q如目l理,另外一个是技术方向,如架构师.的公司可能一人兼多个职位.无论哪个方向都需要大量的实践l验.如果在毕业之前就有项目经验是非常有理?而善于ȝ的h那就能提升自q层次.E序开发h员不应该做ؓ职业的发展目?而是L.
5、在学校里千万不要浪Ҏ?要合理安排学校生z,让学校生zM富而收P“输了这四年你就输了一生”。要提高自己的学习能?要从思想上理?工具是次要的.无论什么语a,到工作的 时候都不够用的.所?我觉得在学校学习的时候要求面q?而不是精?当然,如果你对某一U语a有兴的?_N也无妨,我说的不要精?不是说随便学?我的意思是q个工具应付工程没有问题那就可以?是说可以独立开发一个模?而不要对工程中极用到的一些知识花大力气研I?我说q话?Z学校的时间是不够?其他q要很多需要学习的知识.
我觉得大学里必须要学会的东东:
学会做h(沟通能?成熟,l织能力,理解能力):可以多参加各U社团活?如果没有C֛zd,老乡zd也可?最好自ql?
p(臛_4U?:下点功夫.会有回报?q么说吧,对于四六U证??个证?相当于一个月?000rmb,q么说是不是有吸引力一?
专业评:软g工程,数据l构,数据库知?|络知识
我觉得这四门最为重?q不是说其他的不重要?其他的课上课不缺?考试中等以上可以了.q四门一定要学好.
6、我觉得现在市场的主是j2ee?net两大方向,无论哪个方向,都很有市?要精通的话都不是件容易的事情:)
你可以选择一个方?千万不要问别人选择什么好?q个问题p问篮球好q是毛球好一样难回答,如果你习惯了微Y的品那么就选择.net,如果你喜Ƣ自?不喜Ƣ垄?那么你选择j2ee.多利用网l资?要玩转网l资?不要被网l资源给玩了:)
赯个名字做标题Q是Z让还在读书的朋友要珍惜眼前的旉。其实h生的道\很长Q以前欠的Z后也可以q的。我的意思是q还不如早还Q早q不如不Ơ。不Ơ不如赚?/p>
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=675563
l果Q?br />M从BasezcȝQ都可以利用cout<<obj的机刉过进行输出?br />
同样道理Q也可以利用此方法实现ACE_InputCDR / ACE_OutputCDR对网l操作序列化操作?br />(本文也是回答某网友关于派生类不能重蝲的问题的回复)