??xml version="1.0" encoding="utf-8" standalone="yes"?>
?13?0公分的钉子,一个紧紧插在地上,其他12根如何在不借助外力和外物的条g下放在这个钉?
?54张扑克,一半红Q一半黑Q随机抽取两张,其中有一张是U的Q问另一张是黑的概率是多?
]]>
?
1. 如果最开始有一对兔?8个月后有多少对兔?一q后,两年后呢?
2. 若开始有两对,三对……兔子,?的答案又是多呢Q?br />3. ?对兔子生W一对兔子是?个月后呢Q?个月后?……?上述两题的答案是多少Q?br />
写一D늨序,回答上述所有问题?br />
至今Q我仍能记v当我悟q最l生下面文章时所在的地方。那?986q的夏天Q我在加利福g中国湖v军武器中心担M旉问。在q期_我有q参加了一个关于Ada的研讨会。讨论当中,有一位听众提Z一个具有代表性的问题Q“Y件开发者是工程师吗Q”我不记得当时的回答Q但是我却记得当时ƈ没有真正解答q个问题。于是,我就退论,开始思考我会怎样回答q样一个问题。现在,我无法肯定当时我Z么会记v几乎10q前曄在Datamation杂志上阅读过的一论文,不过促我记L应该是后l讨Z的某些东ѝ这论文阐qC工程师ؓ什么必L好的作家Q我记得该论文谈论就是这个问题——好久没有看了)Q但是我从该论文中得到的关键一ҎQ作者认为工E过E的最l结果是文档。换句话_工程师生产的是文,不是实物。其他hҎq些文d造实物。于是,我就在困惑中提出了一个问题,“除了Y仉目正生的所有文档以外,q有可以被认为是真正的工E文的东西吗?”我l出的回{是Q“是的,有这L文存在Qƈ且只有一份——源代码。?/p>
把源代码看作是一份工E文——设计——完全颠覆了我对自己所选择的职业的看法。它改变了我看待一切事情的方式。此外,我对它思考的多Q我p觉得它阐明了软g目常常遇到的众多问题。更切地说Q我觉得大多Ch不理解这个不同的看法Q或者有意拒l它q样一个事实,p以说明很多问题。几q后Q我l于有机会把我的观点公开发表。C++ Journal中的一有兌Y件设计的论文促我给~辑写了一关于这个主题的信。经q几书信交换后Q编辑Livleen Singh同意把我关于q个主题的想法发表ؓ一论文。下面就是这文章?/p>
——Jack Reecves, December,22,2001
什么是软g设计Q?
Jack W.Reeves, 1992
面向对象技术,特别是C++Q似乎给软g界带来了不小的震动。出C大量的论文和书籍Lq如何应用这Ҏ技术。ȝ来说Q那些关于面向对象技术是否只是一个骗局的问题已l被那些关于如何付出最的努力卛_获得收益的问题所替代。面向对象技术出现已l有一D|间了Q但是这U爆炸式的流行却g有点不寻常。h们ؓ何会H然x它呢Q对于这个问题,Zl出了各U各L解释。事实上Q很可能没有单一的原因。也许,把多U因素的l合h才能最l取得突_q且q项工作正在q展之中。尽如此,在Y仉命的q个最新阶D中QC++本n看v来似乎成Z一个主要因素。同P对于q个问题Q很可能也存在很多种理由Q不q我想从一个稍微不同的视角l出一个答案:C++之所以变得流行,是因为它使Y件设计变得更Ҏ的同Ӟ也ɾ~程变得更容易?/p>
虽然q个解释好像有点奇特Q但是它却是深思熟虑的l果。在q篇论文中,我就是想要关注一下编E和E序设计之间的关pR近10q来Q我一直觉得整个Y件行业都没有觉察到做Z个Y件设计和什么是真正的Y件设计之间的一个微妙的不同炏V只要看Cq一点,我认为我们就可以从C++增长的流行趋势中Q学到关于如何才能成为更好的软g工程师的意义p的知识。这个知识就是,~程不是构徏软gQ而是设计软g?/p>
几年前,我参见了一个讨ZQ其中讨论到软g开发是否是一门工E学U的问题。虽然我不记得了讨论l果Q但是我却记得它是如何促使我认识刎ͼ软g业已l做Z一些错误的和硬件工E的比较Q而忽视了一些绝Ҏ的Ҏ。其实,我认为我们不是Y件工E师Q因为我们没有认识到什么才是真正的软g设计。现在,我对q一Ҏ是确信无疑?/p>
M工程zd的最l目标都是某些类型的文。当设计工作完成Ӟ设计文档p转交l制造团队。该团队是一个和设计团队完全不同的群体,q且其技能也和设计团队完全不同。如果设计文正地描绘了一个完整的设计Q那么制造团队就可以着手构Z品。事实上Q他们可以着手构产品的许多实物,完全无需设计者的Mq一步的介入。在按照我的理解方式审查了Y件开发的生命周期后,我得Z个结论:实际上满_E设计标准的惟一软g文Q就是源代码清单?/p>
对于q个观点Qh们进行了很多的争论,无论是赞成的q是反对的都以写成无数的论文。本文假定最l的源代码就是真正的软g设计Q然后仔l研I了该假定带来的一些结果。我可能无法证明q个观点是正的Q但是我希望证明Q它实解释了Y件行业中一些已l观察到的事实,包括C++的流行?/p>
在把代码看作是Y件设计所带来的结果中Q有一个结果完全盖q了所有其他的l果。它非常重要q且非常明显Q也正因为如此,对于大多数Y件机构来_它完全是一个盲炏V这个结果就是:软g的构建是廉h的。它Ҏ׃h昂贵的资|它非常的廉hQ几乎就是免费的。如果源代码是Y件设计,那么实际的Y件构建就是由~译器和q接器完成的。我们常常把~译和连接一个完整的软gpȝ的过E称为“进行一ơ构建”。在软g构徏讑֤上所q行的主要投资是很少的——实际需要的只有一台计机、一个编辑器、一个编译器以及一个连接器。一旦具有了一个构建环境,那么实际的Y件构建只需p许的时间。编?0 000行的C++E序也许会花费很长的旉Q但是构Z个具有和50 000行C++E序同样设计复杂性的gpȝ要花费多长的旉呢?
把源代码看作是Y件设计的另外一个结果是QY件设计相Ҏ于创作,臛_在机械意义上如此。通常Q编写(也就是设计)一个具有代表性的软g模块Q?0?00行代码)只需p几天的时_对它q行完全的调试是另外一个议题,E后会对它进行更多的讨论Q。我很想问一下,是否q有M其他的学U可以在如此短的旉内,产生出和软gh同样复杂性的设计来,不过Q首先我们必要弄清出如何来度量和比较复杂性。然而,有一Ҏ明显的,那就是Y件设计可?极ؓq速地变得非常庞大?/p>
假设软g设计相对易于创作Qƈ且在本质上构v来也没有什么代P一个不令h吃惊的发现是QY件设计往往是难以置信的庞大和复杂。这看v来似乎很明显Q但是问题的重要性却常常被忽视。学校中的项目通常h数千行的代码。具?0 000行代码(设计Q的软g产品被它们的设计者丢弃的情况也是有的。我们早׃再关注于单的软g。典型的商业软g的设计都是由数十万行代码l成的。许多Y件设计达C上百万行代码。另外,软g设计几乎L在不断地演化。虽然当前的设计可能只有几千行代码,但是在品的生命期中Q实际上可能要编写许多倍的代码?/p>
管实存在一些硬件设计,它们看v来似乎和软g设计一样复杂,但是h意两个有关现代硬件的事实。第一Q复杂的g工程成果未必L没有错误的,在这一点上Q它不存在像软g那样让我们相信的评判标准。多数的微处理器在发售时都具有一些逻辑错误Q桥梁坍塌,大坝破裂Q飞机失事以及数以千计的汽R和其他消费品被召回——所有的q些我们都记忆犹斎ͼ所有的q些都是设计错误的结果。第二,复杂的硬件设计具有与之对应的复杂、昂늚构徏阶段。结果,刉这U系l所需的能力限制了真正能够生复杂g设计公司的数目。对于Y件来_没有q种限制。目前,已经有数以百计的软g机构和数以千计的非常复杂的Y件系l存在,q且数量以及复杂性每天都在增ѝ这意味着软g行业不可能通过仿效g开发者找到针对自w问题的解决办法。倘若一定要说出有什么相同之处的话,那就是,当CAD和CAM可以做到帮助g设计者创来越复杂的设计时Q硬件工E才会变得和软g开发越来越像?/p>
设计软g是一U管理复杂性的zd。复杂性存在于软g设计本n之中Q存在于公司的Y件机构之中,也存在于整个软g行业之中。Y件设计和pȝ设计非常怼。它可以跨越多种技术ƈ且常常涉及多个学U分支。Y件的规格说明往往不固定、经常快速变化,q种变化常常在正q行软g设计时发生。同P软g开发团队也往往不固定,常常在设计过E的中间发生变化。在许多斚wQY仉要比g更像复杂的社会或者有机系l。所有这些都使得软g设计成ؓ了一个困隄q且易出错的q程。虽然所有这些都不是创造性的xQ但是在软g工程革命开始将q?0q后的今天,和其他工E行业相比,软g开发看h仍然像是一U未受过训练QundisciplinedQ的技艺?/p>
一般的看法认ؓQ当真正的工E师完成了一个设计,不管该设计有多么复杂Q他们都非常信该设计是可以工作的。他们也非常信该设计可以用公认的技术徏造出来。ؓ了做到这一点,g工程师花费了大量的时间去验证和改q他们的设计。例如,误虑一个桥梁设计。在q样一个设计实际徏造之前,工程师会q行l构分析——他们徏立计机模型q进行仿真,他们建立比例模型q在风洞中或者用其他一些方法进行测试。简而言之,在徏造前Q设计者会使用他们能够惛_的一切方法来证实设计是正的。对于一架新型客机的设计来说Q情는x加严重;必须要构建出和原物同寸的原型,q且必须要进行飞行测试来验证设计中的U种预计?/p>
对于大多Ch来说QY件中明显不存在和g设计同样严格的工E。然而,如果我们把源代码看做是设计,那么׃发现软g工程师实际上对他们的设计做了大量的验证和改进。Y件工E师不把q称为工E,而称它ؓ试和调试。大多数Z把测试和调试看作是真正的“工E”——在软g行业中肯定没有被看作是。造成q种看法的原因,更多的是因ؓ软g行业拒绝把代码看作设计,而不是Q何实际的工程差别。事实上Q试验模型、原型以及电路试验板已经成ؓ其他工程学科公认的组成部分。Y件设计者之所以不h或者没有用更多的正规Ҏ来验证他们的设计Q是因ؓ软g构徏周期的简单经规律?/p>
W一个启C:仅仅构徏设计q测试它比做M其他事情要廉价一些,也简单一些。我们不兛_做了多少ơ构建——这些构建在旉斚w的代价几乎ؓӞq且如果我们丢弃了构建,那么它所使用的资源完全可以重新利用。请注意Q测试ƈ非仅仅是让当前的设计正确Q它也是改进设计的过E的一部分。复杂系l的g工程师常常徏立模型(或者,臛_他们把设计用计算机图形直观地表现出来Q。这׃得他们获得了对于设计的一U“感觉”,而仅仅去查设计是不可能获得这U感觉的。对于Y件来_构徏q样一个模型既不可能也无必要。我们仅仅构Z品本w。即使正规的软g验证可以和编译器一栯动进行,我们q是会去q行构徏/试循环。因此,正规的验证对于Y件行业来说从来没有太多的实际意义?/p>
q就是现今Y件开发过E的现实。数量不断增长的人和机构正在创徏着更加复杂的Y件设计。这些设计会被先用某些编E语a~写出来Q然后通过构徏/试循环q行验证和改q。过E易于出错,q且不是特别的严根{相当多的Y件开发h员ƈ不想怿q就是过E的q作方式Q也正因一点,佉K题变得更加复杂?/p>
当前大多数的软gq程都试图把软g设计的不同阶D分d不同的类别中。必要在顶层的设计完成q且ȝ后,才能开始编码。测试和调试只对清除建造错误是必要的。程序员处在中间位置Q他们是软g行业的徏造工人。许多h认ؓQ如果我们可以让E序员不再进行“随意的~码QhackingQ”ƈ且按照交l他们的设计去进行构建(q要在过E中Q犯更少的错误)Q那么Y件开发就可以变得成熟Q从而成Z门真正的工程学科。但是,只要q程忽视了工E和l济学事实,q就不可能发生?/p>
例如QQ何一个现代行业都无法忍受在其刉过E中出现过100%的返工率。如果一个徏造工人常怸能在W一ơ就构徏正确Q那么不久他׃׃。但是在软g业中Q即使最的一块代码,在测试和调试期间Q也很可能会被修正或者完全重写。在一个创造性的q程中(比如Q设计)Q我们认可这U改q不是制造过E的一部分。没有h会期望工E师W一ơ就创徏出完的设计。即使她做到了,仍然必须让它l受改进q程Q目的就是ؓ了证明它是完的?/p>
即我们从日本的理Ҏ中没有学CQ何东西,我们也应该知道由于在q程中犯错误而去责备工h是无益于提高生率的。我们不应该不断地强qY件开发去W合不正的q程模型Q相反,我们需要去改进q程Q之有助于而不是阻生更好的软g。这是“Y件工E”的矌试。工E是关于你如何实施过E的Q而不是关于是否需要一个CADpȝ来生最l的设计文?/p>
关于软g开发有一个压倒性的问题Q那是一切都是设计过E的一部分。编码是设计Q测试和调试是设计的一部分Qƈ且我们通常认ؓ的设计仍然是设计的一部分。虽然Y件构v来很廉hQ但是设计v来却是难以置信的昂贵。Y仉常的复杂Q具有众多不同方面的设计内容以及它们所D的设计考虑。问题在于,所有不同方面的内容是相互关q的Q就像硬件工E中的一P。我们希望顶层设计者可以忽视模块算法设计的l节。同P我们希望E序员在设计模块内部法时不必考虑层设计问题。糟p的是,一个设计层面中的问题R入到了其他层面之中。对于整个Y件系l的成功来说Qؓ一个特定模块选择法可能和Q何一个更高层ơ的设计问题同样重要。在软g设计的不同方面内容中Q不存在重要性的{。最低层模块中的一个不正确设计可能和最高层中的错误一栯命。Y件设计必d所有的斚w都是完整和正的Q否则,构徏于该设计基础之上的所有Y仉会是错误的?/p>
Z理复杂性,软g被分层设计。当E序员在考虑一个模块的详细设计Ӟ可能q有C百计的其他模块以及数以千计的l节Q他不可能同旉及。例如,在Y件设计中Q有一些重要方面的内容不是完全属于数据l构和算法的范畴。在理想情况下,E序员不应该在设计代码时q得去考虑设计的这些其他方面的内容?/p>
但是Q设计ƈ不是以这U方式工作的Qƈ且原因也开始变得明朗。Y件设计只有在其被~写和测试后才算完成。测试是设计验证和改q过E的基础部分。高层结构的设计不是完整的Y件设计;它只是细节设计的一个结构框架。在严格地验证高层设计方面,我们的能力是非常有限的。详l设计最l会寚w层设计造成的媄响至和其他的因素一样多Q或者应该允许这U媄响)。对设计的各个方面进行改q,是一个应该诏I整个设计周期的q程。如果设计的M一个方面内容被ȝ在改q过E之外,那么对于最l设计将会是p糕的或者甚x法工作这一点,׃会觉得奇怪了?/p>
如果高层的Y件设计可以成Z个更加严格的工程q程Q那该有多好呀Q但是Y件系l的真实情况不是严格的。Y仉常的复杂Q它依赖于太多的其他东西。或许,某些g没有按照设计者认为的那样工作Q或者一个库例程h一个文中没有说明的限制。每一个Y仉目迟早都会遇到这些种cȝ问题。这些种cȝ问题会在试期间被发玎ͼ如果我们的测试工作做得好的话Q,之所以如此是因ؓ没有办法在早期就发现它们。当它们被发现时Q就q对设计进行更攏V如果我们幸q,那么对设计的更改是局部的。时常,更改会L及到整个软g设计中的一些重要部分(莫非定律Q。当受到影响的设计的一部分׃某种原因不能更改Ӟ那么Z能够适应影响Q设计的其他部分必d遭到破坏。这通常D的结果就是管理者所认ؓ的“随意编码”,但是q就是Y件开发的现实?/p>
例如Q在我最q工作的一个项目中Q发C模块A的内部结构和另一个模块B之间的一个时序依赖关pR糟p的是,模块A的内部结构隐藏在一个抽象体的后面,而该抽象体不允许以Q何方法把Ҏ块B的调用合入到它的正确调用序列中。当问题被发现时Q当然已l错q了更改A的抽象体的时机。正如所料,所发生的就是把一个日益增长的复杂的“修正”集应用到A的内部设计上。在我们q没有安装完版本1Ӟ普遍感觉到设计正在衰退。每一个新的修正很可能都会破坏一些老的修正。这是一个正规的软g开发项目。最后,我和我的同事军_对设计进行更改,但是Z得到理层的同意Q我们不得不自愿无偿加班?/p>
在Q何一般规模的软g目中,肯定会出现像q样的问题,管Z使用了各U方法来防止它的出现Q但是仍然会忽视一些重要的l节。这是工艺和工E之间的区别。如果经验可以把我们引向正确的方向,q就是工艺。如果经验只会把我们带入未知的领域,然后我们必须使用一开始所使用的方法ƈ通过一个受控的改进q程把它变得更好Q这是工程?/p>
我们来看一下只是作为其中很一点的内容Q所有的E序员都知道Q在~码之后而不是之前编写Y件设计文会产生更加准确的文档。现在,原因是显而易见的。用代码来表现的最l设计是惟一一个在构徏/试循环期间被改q的东西。在q个循环期间Q初始设计保持不变的可能性和模块的数量以及项目中E序员的数量成反比。它很快׃变得毫无价倹{?/p>
在Y件工E中Q我们非帔R要在各个层次都优U的设计。我们特别需要优U的顶层设计。初期的设计好Q详l设计就会越Ҏ。设计者应该用Q何可以提供帮助的东西。结构图表、Booch 图、状态表、PDL{等——如果它能够提供帮助Q就M用它。但是,我们必须CQ这些工具和W号都不是Y件设计。最后,我们必须创徏真正的Y件设计,q且是用某U编E语a完成的。因此,当我们得计时Q我们不应该x对它们q行~码。在必要Ӟ我们必须应该乐于Lq它们?/p>
至今Q还没有M设计W号可以同时适用于顶层设计和详细设计。设计最l会表现Z某种~程语言~写的代码。这意味着在详l设计可以开始前Q顶层设计符号必被转换成目标编E语a。这个{换步骤耗费旉q且会引入错误。程序员常常是对需求进行回ƈ且重新进行顶层设计,然后Ҏ它们的实际去q行~码Q而不是从一个可能没有和所选择的编E语a完全映射的符可行{换。这同样也是软g开发的部分现实情况?/p>
也许Q如果让设计者本人来~写初始代码Q而不是后来让其他人去转换语言无关的设计,׃更好一些。我们所需要的是一个适用于各个层ơ设计的l一W号。换句话_我们需要一U编E语aQ它同样也适用于捕获高层的设计概念。CQ+正好可以满q个要求。C++是一门适用于真实项目的~程语言Q同时它也是一个非常具有表辑֊的Y件设计语a。C++允许我们直接表达关于设计lg的高层信息。这P可以更Ҏ地进行设计,q且以后可以更容易地改进设计。由于它h更强大的cd查机Ӟ所以也有助于检到设计中的错误。这׃生了一个更加健壮的设计Q实际上也是一个更好的工程化设计?/p>
最后,软g设计必须要用某种~程语言表现出来Q然后通过一个构?试循环对其q行验证和改q。除此之外的M其他d都完全没有用。请考虑一下都有哪些Y件开发工具和技术得以流行。结构化~程在它的时代被认ؓ是创造性的技术。Pascal使之变得行Q从而自׃变得行。面向对象设计是新的行技术,而C++是它的核心。现在,误虑一下那些没有成效的东西。CASE工具Q流行吗Q是的;通用吗?不是。结构图表怎么P情况也一栗同样地Q还有Warner-Orr图、Booch图、对象图以及你能惌v的一切。每一个都有自q强项Q以及惟一的一个根本弱点——它不是真正的Y件设计。事实上Q惟一一个可以被普遍认可的Y件设计符hPDLQ而它看v来像什么呢Q?/p>
q表明,在Y件业的共同潜意识中本能地知道Q编E技术,特别是实际开发所使用的编E语a的改q和软g行业中Q何其他东西相比,h压倒性的重要性。这q表明,E序员关心的是设计。当出现更加h表达力的~程语言Ӟ软g开发者就会用它们?/p>
同样Q请考虑一下Y件开发过E是如何变化的。从前,我们使用瀑布式过E。现在,我们谈论的是螺旋式开发和快速原型。虽然这U技术常常被认ؓ可以“消除风险”以及“羃短品的交付旉”,但是它们事实上也只是Z在Y件的生命周期中更早地开始编码。这是好事。这使得构徏/试循环可以更早地开始对设计q行验证和改q。这同样也意味着Q顶层Y件设计者很有可能也会去q行详细设计?/p>
正如上面所表明的,工程更多的是关于如何d施过E的Q而不是关于最l品看h的像什么。处在Y件行业中的我们,已经接近工程师的标准Q但是我们需要一些认知上的改变。编E和构徏/试循环是工EY件过E的中心。我们需要以像这L方式ȝ理它们。构?试循环的经规律,再加上Y件系l几乎可以表CQ何东西的事实Q就使得我们完全不可能找ZU通用的方法来验证软g设计。我们可以改善这个过E,但是我们不能q它?/p>
最后一点:M工程设计目的目标是一些文档品。显Ӟ实际设计的文是最重要的,但是它们q惟一要生的文。最l,会期望某些h来用Y件。同Ppȝ很可能也需要后l的修改和增强。这意味着Q和g目一P辅助文对于软g目h同样的重要性。虽然暂时忽略了用户手册、安装指南以及其他一些和设计q程没有直接联系的文,但是仍然有两个重要的需求需要用辅助设计文档来解决?/p>
辅助文档的第一个用途是从问题空间中捕获重要的信息,q些信息是不能直接在设计中用的。Y件设计需要创造一些Y件概忉|寚w题空间中的概念进行徏模。这个过E需要我们得Z个对问题I间中概늚理解。通常Q这个理解中会包含一些最后不会被直接建模到Y件空间中的信息,但是q些信息却仍然有助于设计者确定什么是本质概念以及如何最好地对它们徏模。这些信息应该被记录在某处,以防以后要去更改模型?/p>
对辅助文的W二个重要需要是对设计的某些斚w的内容进行记录,而这些方面的内容是难以直接从设计本n中提取的。它们既可以是高层方面的内容Q也可以是低层方面内宏V对于这些方面内容中的许多来_囑Ş是最好的描述方式。这׃得它们难以作为注释包含在代码中。这q不是说要用囑Ş化的软g设计W号代替~程语言。这和用一些文本描q来对硬件科目的囑Ş化设计文进行补充没有什么区别?/p>
决不要忘讎ͼ是源代码军_了实际设计的真实样子Q而不是辅助文档。在理想情况下,可以使用软g工具Ҏ代码q行后期处理q生出辅助文。对于这一点,我们可能期望q高了。次一点的情况是,E序员(或者技术方面的~写者)可以使用一些工具从源代码中提取Z些特定的信息Q然后可以把q些信息以其他一些方式文档化。毫无疑问,手工对这U文保持更新是困难的。这是另外一个支持需要更兯辑֊的编E语a的理由。同Pq也是一个支持ɘq种辅助文保持最ƈ且尽可能在项目晚期才使之变成正式的理由。同P我们可以使用一些好的工P不然的话Q我们就得求助于铅笔、纸以及黑板?/p>
ȝ如下Q?
实际的Y件运行于计算Z中。它是存储在某种介质中??的序列。它不是使用C++语言Q或者其他Q何编E语aQ编写的E序?
E序清单是代表Y件设计的文。实际上把Y件设计构建出来的是编译器和连接器?
构徏实际软g设计的廉L度是令h难以|信的,q且它始l随着计算机速度的加快而变得更加廉仗?
设计实际软g的昂늨度是令h难以|信的,之所以如此,是因Y件的复杂性是令h难以|信的,q且软g目的几乎所有步骤都是设计过E的一部分?
~程是一U设计活动——好的Y件设计过E认可这一点,q且在编码显得有意义Ӟ׃毫不犹U的去~码?
~码要比我们所认ؓ的更频繁地显现出它的意义。通常Q在代码中表现设计的q程会揭C出一些疏漏以及额外的设计需要。这发生的越早,设计׃好?
因ؓ软g构徏h非常廉hQ所以正规的工程验证Ҏ在实际的软g开发中没有多大用处。仅仅徏造设计ƈ试它要比试囑֎证明它更单、更廉h?
试和调试是设计zd——对于Y件来_它们q当于其他工程学科中的设计验证和改q过E。好的Y件设计过E认可这一点,q且不会试图d这些步骤?
q有一些其他的设计zd——称它们为高层设计、模块设计、结构设计、构架设计或者诸如此cȝ东西。好的Y件设计过E认可这一点,q且慎重地包含这些步骤?
所有的设计zd都是怺影响的。好的Y件设计过E认可这一点,q且当不同的设计步骤昄出有必要Ӟ它会允许设计改变Q有时甚xҎ上的改变Q?
许多不同的Y件设计符号可能是有用的——它们可以作助文以及工h帮助化设计过E。它们不是Y件设计?
软g开发仍然还是一门工艺,而不是一个工E学U。主要是因ؓ~Z验证和改善设计的关键q程中所需的严格性?
最后,软g开发的真正q步依赖于编E技术的q步Q而这又意味着~程语言的进步。C++是q样的一个进步。它已经取得了爆炸式的流行,因ؓ它是一门直接支持更好的软g设计的主编E语a?
C++在正的方向上迈Z一步,但是q需要更大的q步?/p>
??/p>
当我回顾几乎10q前所写的东西Ӟ有几点让我印象深刅R第一点(也是和本书最有关的)是,CQ我甚至比那时更加确信我试图去阐q的要点在本质上的正性。随后的一些年中,许多行的Y件开发方法增Z其中的许多观点,q支持了我的信念。最明显的(或许也是最不重要的Q是面向对象~程语言的流行。现在,除了C++外,出现了许多其他的面向对象~程语言。另外,q有一些面向对象设计符P比如QUML。我关于面向对象语言之所以得到流行是因ؓ它们允许在代码中直接表现出更兯辑֊的设计的论点Q现在看来有点过时了?/p>
重构的概念——重新组l代码基Q之更加健壮和可重用——同样也和我的关于设计的所有方面的内容都应该是灉|的ƈ且在验证设计时允许改变的论点怼。重构只是提供了一个过E以及一l如何去改善已经被证实具有缺L设计的准则?/p>
最后,文中有一个敏捷开发的ȝ概念。虽然极限编E是q些新方法中最知名的一个,但是它们都具有一个共同点Q它们都承认源代码是软g开发工作中的最重要的品?/p>
另一斚wQ有一些观点——其中的一些我在论文中略微谈到q——在随后的一些年中,Ҏ来说变得更加重要。第一个是构架Q或者顶层设计的重要性。在论文中,我认为构架只是设计的一部分内容Qƈ且在构徏/试循环对设计进行验证的q程中,构架需要保持可变。这在本质上是正的Q但是回惌v来,我认为我的想法有点不成熟。虽然构?试循环可能揭示出构架中的问题,但是更多的问题是常常׃改变需求而表现出来的?一般来_设计软g是困隄Qƈ且新的编E语aQ比如:Java或者C++Q以及图形化的符P比如QUMLQ对于不知道如何有效C用它的h来说Q都没有多大的帮助。此外,一旦一个项目基于一个构架构Z大量的代码,那么对该构架q行基础性的更改Q常常相当于丢弃掉该目q新开始一个,q就意味着该项目没有出现过。即佉K目和机构在根本上接受了重构的概念Q但是他们通常仍然不愿意去做一些看h像是完全重写的事情。这意味着W一ơ就把它作对Q或者至是接近对)是重要的Qƈ且项目变得越大,p要如此。幸q的是,软g设计模式有助于解册斚w问题?/p>
q有其他一些方面的内容Q我认ؓ需要更多地一下,其中之一是辅助文档Q尤其是构架斚w的文。虽然源代码是设计Q但是试图从源代码中得出构架Q可能是一个o人畏惧的体验。在论文中,我希望能够出C些Y件工h帮助软g开发者自动地l护来自源代码的辅助文档。我几乎已经攑ּ了这个希望。一个好的面向对象构枉常可以使用几幅图以及少许的十几|本描q出来。不q,q些图(和文本)必须集中于设计中的关键类和关pR糟p的是,对于软g设计工具可能会变得够聪明,以至于可以从源代码的大量l节中提取出q些重要斚w的内容这一点,我没有看CQ何真正的希望。这意味着q得必须׃h来编写和l护q种文档。我仍然认ؓQ在源代码完成后Q或者至是在编写源代码的同时去~文,要比在编写源代码之前ȝ写文档更好一些?/p>
最后,我在论文的最后谈CC++是编E——ƈ且因此是软g设计——艺术的一个进步,但是q需要更大的q步。就我完全没有看到语言中出CQ何真正的~程q步来挑战C++的流行,那么在今天,我会认ؓq一点甚臌比我首次~写它时更加正确?/p>
——Jack Reeves, 2002q???
#注:本脚本需要以用户w䆾q行?/p>
# 监测的时间间隔,U计
INTERVAL=60
# 重启旉间隔
INTERVALRESTART=1
#==================================================================
PROGRAME=program
THREADNUMS=1
LOG=/apps/server/monitor.log
#SYSDATE=$(date)
SYSBUILD=`/bin/cat /etc/redhat-release | /bin/awk '{print $5$7}'`
var="-emf"
case ${SYSBUILD} in
"7.3")
var="-e"
;;
"8.0")
var="-em"
;;
"AS3")
var="-emf"
;;
esac
while true
do
SYSDATE=$(date)
nowps1=`ps $var | grep $PROGRAME | grep -v grep | wc -l`
nowps1=`expr $nowps1`
if [ $nowps1 -lt $THREADNUMS ]; then
/bin/sh /apps/program.sh
echo " " >> $LOG
echo "*******************************************************" >> $LOG
echo "Restart time:" $SYSDATE >> $LOG
echo "---------- Program $PROGRAME restart ----------------" >> $LOG
echo "*******************************************************" >> $LOG
echo " "
fi
sleep $INTERVAL
done
#-----------------------------------------------------------
exit 0
在文?etc/rc.local在其中增加一个启动项Q即在文件末֢加一条可执行语句(如:/bin/sh /apps/program.sh)
看门狗制作完毕?br />
public Class School
{
private ArrayList students;
private void addStudent(Person person)
{
students.add(person);
}
}
l合则是比聚合更强的兌形式。组合是指带有很强的拥有有关pM整体与部分的生命周期一致的聚合兌形式。例如Windows的窗口和H口上的菜单是l合关系。生命周期一致指的是部分必须在组合创建的同时或者之后创建,在组合销毁之前或者同旉毁,部分的生命周期不会超
出组合的生命周期。组合是用带实心菱Ş的实U来表示?br />public Class Menu
{...}
public Class Window
{
private Menu menu;
}
l合和聚合在代码实现上的主要差别在于生命周期的实CQ组成需要负责其部分的创建和销毁?br />public Class School
{
public School()
{...}//不需要创ZQ何Person对象Q其Students都是已有的Person对象
public void destroy()
{...}//只需要关掉School对象和断开它与自己所有的Person对象的关联即可,Person对象是不会销毁的
}
public Class Window
{
private Menu menu;
public Window()
{
menu = new Menu();
}//可以在这时候创建Menu对象Q也可以在之后创?br />public void destory()
{
menu.destory();
}//必须同时或者在q之前销毁关联的Menu对象
}
另外有一个差别是l合中的一个对象在同一时刻只能属于一个组成对象,而聚合的一个部分对象可以被多个整体对象聚合Q例如一个学生可以在多个学校pQ而一个菜单在同一时刻只能是某个窗口内的对象?
实现关系比较简单了Q指的是一个类元描qC另一个类元保证实现的契约。对cL_是一个类实现了一个接?br />public interface A
{
public void methodA();
}
public class B implements A
{
public void methodA()
{...}
...
}
一般在面对对象的系l中Q尽可能的用接口来减少cM间的耦合。因为接口没有实玎ͼ所以依赖于接口׃会依赖于某种具体实现Q例如jdbc里的Connection和ResultSet都是接口Q不同数据库厂商的实现可以不一栗?br />
ȝ一?br />1)依赖关系Q关pd象出现在局部变量或者方法的参数里,或者关pȝ的静态方法被调用
2)兌关系Q关pd象出现在实例变量?br />3)聚合关系:关系对象出现在实例变量中
4)合成关系Q关pd象出现在实例变量?br />5)Generalization: extends
6)实现Q? implements
聚合是这LQ学生与所选课E之间的关系是l合Q他们之间在感念上没有必然关p,删掉一门课E,不会影响到学?
l合是这LQ订单和订单条目的关pd是聚合,他们的关pd紧密Q删掉一个订单,订单条目也就没有意义?br />l合是聚合的一UŞ?/p>
export LANG=zh_CN.GB2312
/bin/echo -e "start program!" >> /p2p.log
ps -ef|grep 'program' |grep -v grep |awk '{print $2}' |xargs -t -l kill -9
nohup /usr/java/jdk1.5.0_08/bin/java -jar /apps/program.jar 1>program.log&
启动时sh program.sh卛_
二、看门狗shell脚本 monitor.sh
#!/bin/bash
#注:本脚本需要以用户w䆾q行?/p>
# 监测的时间间隔,U计
INTERVAL=60
# 重启旉间隔
INTERVALRESTART=1
#==================================================================
PROGRAME=program
THREADNUMS=1
LOG=/apps/monitor.log
#SYSDATE=$(date)
while true
do
#echo " "
#echo "**********Now begin to monitor program's status , please wait.************"
#echo " "
#`ulimit -c unlimited`
SYSDATE=$(date)
nowps1=`ps -e | grep $PROGRAME | grep -v grep | wc -l`
nowps1=`expr $nowps1`
#echo "ps = $nowps1"
if [ $nowps1 -lt $THREADNUMS ]; then
/usr/bin/killall -9 $PROGRAME 1>/dev/null 2>/dev/null
echo "======================================================" >> $LOG
echo "Restart date:" $SYSDATE >> $LOG
echo "Program name:" $PROGRAME >> $LOG
echo "======================================================" >> $LOG
#sleep $INTERVALRESTART
# ./$PROGRAME 1>ucfile 2>ucfile
/bin/sh /apps/server/p2pstart.sh
echo " "
echo "*******************************************************"
echo "---------- Program $PROGRAME restart ----------------"
echo "*******************************************************"
echo " "
fi
#echo "**********Now ended monitor program's status !*************************"
#echo " "
sleep $INTERVAL
done
#-----------------------------------------------------------
exit 0
如何在系l启动时启动看门狗程序:
早上所有hȝ别h的狗Q晚上若能确定自己家狗是疯狗杀!(不能看自q狗)Q如看不到别人有疯狗Q则自己家ؓ疯狗Q?/p>
W一天晚上,无h杀狗?/p>
W二天晚上,无h杀狗?/p>
W三天晚上,疯狗全被杀Q?/p>
问:有几只疯狗?