16

对于没有读过 Code Complete 2 的人来说,Pseudocode Programming Process 基本上是一种设计例程的方法,先用通俗的英语描述,然后逐步修改为更详细的伪代码,最后是代码。这样做的主要好处是通过自上而下而不是自下而上构建系统来帮助您保持在正确的抽象级别,从而在不同的层中发展出干净的 API。我发现 TDD 在这方面不太有效,因为它过于关注做最少的事情以使测试通过,并且鼓励很少的前期设计。我还发现必须为不稳定的代码(不断被重构的代码)维护一套单元测试是相当困难的,因为通常情况下,你需要为一个只需要一次或两次的例程进行十几个单元测试。当你进行重构时——例如更改方法签名——你所做的大部分工作是更新测试而不是更新产品代码。我更喜欢在组件的代码稍微稳定后添加单元测试。

我的问题是——在尝试过这两种方法的人中,你更喜欢哪一种?

4

6 回答 6

6

我的团队混合了这两种方法,这是一种很棒的开发方式(至少对我们而言)。我们需要单元测试,因为我们有一个庞大而复杂的软件系统。但是伪代码编程过程无疑是我遇到的最好的软件设计方法。为了让它们一起工作:

  • 我们首先编写我们的类,并用完全注释的方法存根填充输入和输出。
  • 我们使用结对编码和同行评审作为对话来改进和验证设计,仍然只使用方法存根。
  • 在这一点上,我们现在既设计了我们的系统,也有了一些可测试的代码。所以我们继续编写我们的单元测试。
  • 我们返回并开始在方法中填写需要编写的逻辑注释。
  • 我们写代码;测试通过。

它的美妙之处在于,当我们真正编写代码时,大部分实现工作已经完成,因为我们认为实现的大部分内容实际上是代码设计。此外,早期过程取代了对 UML 的需求——类和方法存根具有描述性,而且它实际上会被使用。而且我们总是停留在适当的抽象级别。

显然,这个过程从来没有像我所描述的那样真正线性 - 一些实现的怪癖可能意味着我们需要重新审视高级设计。但总的来说,当我们编写单元测试时,设计真的很稳定(在方法级别),所以不需要大量的测试重写。

于 2010-04-02T10:04:11.667 回答
4

使用测试驱动开发,您仍然应该在开始时进行一些规划。首先应该是对您正在尝试做的事情进行高层次的了解。不要想出所有的细节,而是用简单的英语了解如何解决问题。

然后开始测试问题。一旦你完成了测试,就开始让它通过。如果这不容易做到,您可能需要修改您的初始计划。有问题就修改。测试不是为了定义解决方案,它允许您进行更改,以便您可以在确保稳定性的同时获得更好的解决方案。

我想说最好的选择是使用 TDD。关键是要认识到 TDD 并不意味着“跳过计划”。TDD 意味着做一些计划以顺利开始,并根据需要进行调整。你甚至可能不需要调整。

于 2008-10-03T21:51:15.873 回答
3

一般来说,我发现伪代码只有在解决问题所需的代码比测试解决方案所需的代码复杂得多时才真正相关。如果不是这种情况,我不会遇到您所描述的困难,因为最简单的事情可能有效,通常是一个可接受的解决方案,值得花在问题上的时间量。

另一方面,如果问题复杂,我需要考虑如何解决它,然后才能编写一个初始的幼稚解决方案——我仍然需要在编写代码之前进行计划;因此,我使用了两种方法的组合:我将最初编写的内容的英文描述,然后是测试工具,然后是简单的解决方案代码,然后是细化。

于 2008-10-03T21:55:17.860 回答
1

我已经将这两种方法与 Big Upfront Development 一起使用,这三种方法都有各自的位置,具体取决于语言、团队动态和程序大小/复杂性等问题。

在动态语言(尤其是 ruby​​)中,我强烈推荐 TDD,它可以帮助您捕获其他语言在编译时会捕获的错误。

在一个大型、复杂的系统中,您预先做的设计越多,您的情况就会越好。似乎当我为一个大型项目进行设计时,我挥手并说“这应该是相当直截了当”的每个区域都是项目后期的一个绊脚石。

如果您正在使用静态类型语言单独处理一些小问题,那么列表方法是合理的,并且会为您节省大量的 TDD 时间(测试维护不是免费的,尽管首先编写测试并不是太不好)--当您正在处理的系统中没有任何测试时,添加测试并不总是令人钦佩,您甚至可能会引起一些不必要的注意。

于 2008-10-03T22:22:40.550 回答
1

仅仅因为测试通过,并不意味着你已经完成了。

TDD 的最佳特点是Red-Green-Refactor

有一个测试提供一个(两个)目标线。这只是第一个,最小的一组要求。真正的目标与“伪代码编程过程”或任何设计学科的目标相同。

此外,TDD 是由测试驱动的,但这并不意味着盲目地由测试驱动。您可以像迭代代码一样迭代测试。这里没有教条坚持愚蠢计划的地方。这是一种敏捷技术——这意味着将其适应您的团队和您的环境。

设计足够的代码以具有可测试的接口。设计足够多的测试以确保接口能够正常工作。设计更多的测试和更多的实现,直到你看到重构的需要。

真正的目标是好的软件。TDD 不能排除“善良”。

技术不是限制性要求。应该将技术视为帮助您生产出良好代码的拐杖。如果我更聪明、更富有、更漂亮,我就不需要 TDD。但由于我和我一样笨,我需要一个拐杖来帮助我重构。

于 2008-10-03T23:18:45.773 回答
0

对我来说,TDD 有一个无法与之竞争的王牌伪代码——它们都可以帮助您抽象和规划开发,但是一旦您在 TDD 领域完成了开发,您仍然拥有单元测试

作为 CC2 描述的伪编码的有用方法,它无法与之匹敌。TDD 只是设计的一半,它还提供了一个严格的脚手架,您可以从中发展项目。但是我看不出为什么你不能用伪代码来解决 TDD 设置的问题。

我不能有机地发展。
伪代码是心灵杀手。
导致项目记忆遗忘的是小死亡。
我将面对我 90 后的方法论。
我会允许它越过我并穿过我。
当它过去时,我会转动内在的眼睛,看看它的路径。
伪代码去了哪里,哪里就有 TDD。
只保留单元测试。

(请不要为此而责骂我,我只是半认真的:P)

于 2009-01-05T09:22:08.293 回答