目录编辑器
设计软件是困难的,因此你对如何构建一个模块或系统的最初想法不太可能产生最好的设计。若是您为每一个主要的设计决策考虑多个选项,您将获得一个更好的结果:设计两次。性能
假设您正在为GUI文本编辑器设计管理文件文本的类。第一步是定义类将呈现给编辑器其他部分的接口;与其选择第一个出如今脑海中的想法,不如考虑几种可能性。一种选择是面向行的接口,它具备插入、修改和删除整行文本的操做。另外一个选项是基于单个字符插入和删除的接口。第三种选择是面向字符串的接口,它能够跨行操做任意范围的字符。你不须要肯定每种选择的每一个特性;在这一点上,勾勒出几个最重要的方法就足够了。设计
尝试选择那些彼此大相径庭的方法,这样你会学到更多。 即便您肯定只有一种合理的方法,不管您认为第二种设计有多糟糕,都要考虑采用第二种设计。思考该设计的弱点并将其与其余设计的特色进行对比将是有益的。接口
在你草拟出可供选择的设计方案后,列出每种方案的优缺点。对于接口最重要的考虑是对于高级软件的易用性。在上面的例子中,面向行的接口和面向字符的接口都须要在使用text类的软件中进行额外的工做。在部分行和多行操做(如剪切和粘贴选择)期间,面向行的界面将须要更高级别的软件来分割和链接行。面向字符的接口将须要循环来实现修改多个字符的操做。这也值得考虑其余因素:字符串
一旦你比较了不一样的设计,你就能更好地肯定最佳的设计。最好的选择多是一个备选方案,或者您可能会发现能够将多个备选方案的功能组合到一个比任何原始选择更好的新设计中。it
有时,没有一种选择特别有吸引力,当这种状况发生时,看看是否能够提出其余方案。使用您在最初的替代方案中肯定的问题来驱动新的设计。若是您正在设计文本类,而且只考虑面向行的和面向字符的方法,那么您可能会注意到每种替代方法都很笨拙,由于它须要更高级别的软件来执行额外的文本操做。这是一个危险信号:若是有一个文本类,它应该处理全部的文本操做。为了消除额外的文本操做,文本界面须要更紧密地匹配发生在高级软件中的操做。这些操做并不老是对应于单个字符或单个行。这一行推理应该会为文本提供面向范围的API,从而消除了早期设计的问题。class
两次设计原则能够应用于系统的许多层次。对于模块,您能够首先使用这种方法来选择接口,如上所述。而后您能够在设计实现时再次应用它:对于text类,您能够考虑诸如行链表、固定大小的字符块或“间隙缓冲区”之类的实现。“实现的目标和接口的目标是不一样的:对于实现来讲,最重要的是简单性和性能。在系统的更高层次上探索多种设计也颇有用,好比什么时候为用户界面选择特性,或者什么时候将系统分解为主要模块。在每种状况下,若是您能够比较几个备选方案,就更容易肯定最佳方法。软件
设计两次并不须要花费不少额外的时间。对于较小的模块(如类),您可能不须要超过一两个小时的时间来考虑替代方案。与您将花费几天或几周的时间来实现这个类相比,这只是一小部分时间。最初的设计实验极可能会产生一个更好的设计,这将比花两次时间来设计要好得多。对于较大的模块,您将在最初的设计探索中花费更多的时间,可是实现也会花费更长的时间,并且更好的设计的好处也会更大。循环
我注意到“两次设计”的原则有时很难被真正聪明的人所接受。当他们长大后,聪明的人发现他们对任何问题的第一个快速想法就足以得到一个好成绩;没有必要考虑第二种或第三种可能性。这很容易养成很差的工做习惯。然而,随着这些人年龄的增加,他们会被提高到愈来愈困难的环境中。最终,每一个人都会到达一个临界点,你的第一个想法再也不足够好;若是你想得到真正好的结果,你必须考虑第二种可能,或者第三种,无论你有多聪明。大型软件系统的设计就属于这一类:没有人有足够的能力在第一次尝试时就把它作好。文本编辑器
不幸的是,我常常看到聪明的人坚持执行他们脑海中出现的第一个想法,这致使他们没有发挥出他们真正的潜力(这也让他们在工做中感到沮丧)。也许他们潜意识里认为“聪明人第一次就能成功”,因此若是他们尝试多种设计,那就意味着他们根本不聪明。事实并不是如此。这并非说你不聪明,问题是真的很难。此外,这是一件好事:解决一个须要仔细思考的难题要比解决一个根本不须要思考的简单问题有趣得多。
两次设计的方法不只提升了你的设计,也提升了你的设计能力。设计和比较多种方法的过程将教会您使设计更好或更差的因素。 随着时间的推移,这将使你更容易排除糟糕的设计,并专一于真正伟大的设计。