通过编码进行设计,这是错误的,但更易于可视化
我敢肯定,其他人也同意,当代码触及人行道时,考虑将要包含在应用程序中的所有元素要容易得多。意思是,一旦开始,我们会想到下一步,因为我们已经到达必须设计另一个表或者类的地步。
这种方法的缺点很明显,我们无需赘述。
问题是,对于那些无法"不看"就无法将设计概念化的人,我们如何从裤子所在地的设计过渡到更为结构化的方法论?
我能想到的唯一解决方案是详细的规范,这迫使人们仔细考虑事物的工作方式。
这仅仅是人们如何不同思维的一个例子,还是我忽略了其他事情?
解决方案
回答
好吧,我不知道这是否就是我们要问的,但是阅读此问题强烈使我想起了TDD(测试驱动开发)。
TDD的目标是产生干净,可测试的代码以及一套自动化回归测试。
对我来说,令人惊奇的是,当我们使用TDD进行处理时,代码最终会变得干净整洁……我们思考问题,为其编写测试,实施以使测试通过,然后进行重构以确保代码清晰易读。
我认为我们确实不需要使用TDD进行大量的前期设计,但这可能会有所帮助...我有点支持"通过编码进行设计",但是与此同时,我们可能会遇到重大缺陷如果我们从更大的角度考虑这个问题,即使是很小的时间也是如此。
回答
如果我们还没有看过Martin Fowler的这本书Refactoring,那么我们确实应该阅读。犯罪并不仅仅是快速的原型开发/发展,而是要知道如何在相当短的时间内将持续存在的一点点变成更容易维护的东西。是的,我们会在旅途中发现新的物体,现在花一些时间清理并推进。通常,与尝试事先设计大多数解决方案相比,我们最终会得到更好的产品。
回答
我们正在做极限编程的一部分,甚至没有意识到。从Wiki:
BigDesignUpFront is avoided because YouArentGonnaNeedIt. However, once the SimplestThing is done the programmers RefactorMercilessly, because in the end things should be expressed OnceAndOnlyOnce. Read more about SubsystemsInXp.
事实证明,这种编程不一定是错误的。这全都与我们使用的方法以及可以做什么来更好地推动自己的成功有关。
回答
测试驱动开发(TDD)是一种立即浮现的技术,可支持我们现有的"编码设计"实践。如果实施得当,这将使我们放心地重构代码,这对于逐步发展设计至关重要。
顺便说一句,TDD与Scrum风格的项目管理方法很好地结合在一起,通常也很少使用文档。
敏捷的口头禅之一是提早发布并经常发布。听起来我们已经在做类似的事情,我们只需要将结构放在适当的位置,以便我们可以响应设计中的更改而不必担心破坏代码。
回答
我们现在几乎正在执行此操作,因为遵循从头开始编写的设计规范是麻烦的雷区。我们可以预先设计,但是必须做好准备,最终在编写代码时会丢弃或者重新设计大部分设计。在我看来,无论我们是否进行TDD,都必须通过编码进行设计以验证初始设计。
记住孩子们:冻结设计规范,然后再编码是愚蠢的。
我并不是说我们不应该预先设计,因为在某些情况下代码编写之前会先思考。我们应该可以自己平衡编码和设计配额。如果我们非常了解直觉,那么应该如何计划代码,然后再计划。如果我们不这样做,请对其进行修改,然后重新设计(即重构)。
回答
我不同意在编码时进行设计是错误的观点。
实际上,我非常支持编码就是设计这一观点。编程不是一项机械工作,而是一项创新工作,我们需要一直在各种实现方案之间做出决策。
我并不反对规格或者体系结构设计,但是可以肯定的是,当体系结构文档完成时,设计工作不会结束。
回答
只是几点。
在每一代人中……我们会发现人们渴望采用最新的方法论并加以使用。我是一名早期测试人员,这意味着我通常会测试出现的每个新事物,但是...
关于TDD,实际上,为什么还要在编写代码之前就编写Test?测试的目的是……好吧,要测试某件东西,我们不需要为可能不需要编码测试的东西编写测试代码。也许我们会用完时间(我们知道一些项目进度表),也许测试本身是如此复杂,所以我们需要对其进行验证以证明它是正确的。我们工作是为了生存,而不是相反,我们编写一些测试以测试一些代码,而不是相反。另外,请记住,这是业务,必须有回报率,使某件事变得完美但没有得到报酬的利润是零,无论它多么好。
关于通过编码进行设计。认真地说,这适用于生活中的各个方面,事前思考(说话之前要思考)。在进行设计之前思考会出什么问题?拿一支笔和一张纸,草绘设计,计划一些课程,尝试想象一下它将首先做什么,其次是系统的各个部分,最后如何进行关联。然后,我们可以开始考虑将如何实施。在不考虑自己在做什么的情况下开始编码有什么意义?
如果我们不能在一张纸上考虑一下设计,如果我们只能考虑要编写的代码,那么抱歉,我们不是构建系统的合适人选,但不要在开始设计之前就开始进行编码设计。代码是有生命的实体,设计也是有生命的实体,这意味着它们应该在开发过程中不断发展和适应,但不应轻视或者匆忙投入。
编辑:我知道我在TDD上很努力,很抱歉,我愿意听听经验,但是我仍然希望在大型项目中找到TDD的一种用法(比如说超过7000个工作小时)使用了TDD。我的意思是,涉及确切日期和金钱的真实项目。
回答
灵活的BDUF(前期大设计)。进行BDUF可以捕获所有需要注意的陷阱和事情,一旦我们击中了代码,尽管我们需要灵活使用BDUF,则其中的某些部分可能是完全错误的。
同时使用两者,但要保持常识。
回答
我同意人们在这里所说的大部分内容,但是我认为需要更详细的描述:
@public static:关于提前设计的问题,发言就处在……即使我们是那些非常聪明的人之一,天才之极,我们也无法预先设计整个系统。我们可能以为可以,但是却在自欺欺人。就像他们说的那样,这个问题的根源是"上帝在细节中"。在前面钉上合适的设计的想法纯属自大。但是...这并不意味着我们不应该花任何时间进行前期设计。
让我们来看看"设计"系统的目的是什么:
首先,我们需要一个框架来考虑。我们是否曾经尝试过启动一个新项目?最难的部分是编写第一行。为什么?因为我们有作家障碍,所以我们不知道要去哪里。例如,假设我们要编写计算机游戏,将其称为" NotSoFarShout",它将成为下一个超酷的第一人称射击游戏,它将征服世界并使我们永远富裕。让我们通过编码来设计...
我们将从程序的" main"功能开始:
void main(){ // Um, what the h*** should I put in "main"?! }
因此,也许通过编码进行设计不是正确的决定。让我们尝试另一种方式:
我们计划编写第一人称射击游戏。无论如何,第一人称射击游戏是什么?好的,大致来说,这是一个3D世界,那里有一个玩家角色,NPC(非玩家角色,例如坏人,好人,怪物,沙鼠等),物体(树木,建筑物,汽车)。从玩家角色的角度看世界。玩家角色可以获得各种物品,例如武器,弹药,医疗包等。还有数不胜数的其他内容描述了第一人称射击游戏,但让我们继续前进。
我知道第一人称射击游戏肯定要花费一两个星期以上的时间。我什至会如何开始?我从一点开始,然后逐步编写和设计系统。因此,我选择了一个可以在概念上把握的短期可实现的短期目标,并实际思考如何实现,例如,我将从3D世界的可视化开始。我知道那里有一些不错的3-D引擎,我将做一些研究,挑选一个引擎,然后让它展示我的世界,该世界目前是由漂浮在空隙中的单个球体组成的。这应该花费不超过一两个星期的时间。
OK完成。没花我两周时间,我花了三周时间,但是现在我有了一些基础。接下来,我可能会决定我现在想要构建一个静态静态场景,没有任何动作,没有AI,没有特殊含义的对象,人物等。现在是设计部分……当我开始考虑描绘场景时,不同的方面我会想到3-D世界
- 我的场景描绘了两个站在沙漠中的人,其中一个完全被晒伤,另一个穿着西装和帽子,手里拿着枪。
- 问题1:如何描述场景的内容? 3-D引擎需要特定的表示形式才能渲染场景。它直观且易于使用吗?如果我想改变场景并将枪支移到角色的另一只手上,这有多难?如果我想将其移至其他角色该怎么办?如果我想添加第三个人怎么办?这有多难?如果我想在场景中的任意位置增加100个人,每个人随机拥有枪支和/或者帽子,该怎么办?
- 问题2:如果我希望角色的肤色随时间变化怎么办?例如,字符之一被晒黑了。如果另一个人在这个沙漠场景中停留了足够长的时间,我是否也希望她也逐渐被晒伤?
- 问题3:场景中有阳光,但是我希望它随时间变化-假设游戏中每一分钟的实时时间等于1小时,所以我想让阳光在天空中移动逐渐变成夜晚,有或者没有月亮。也许我希望月亮随着白天和夜晚的流逝而经历它的各个阶段。我要如何表示呢?
这个冗长的示例的想法是概述设计中的这些问题:
- 有多个设计级别。在开始编写产品/子系统/非常大的模块时,我们通常只能执行非常高级的设计。也就是说,我们可以定义基本的大型实体,例如我们的示例:3-D引擎,存储,网络等。这一点很重要,因此我们可以选择要从哪里开始,认为最大的风险在哪里等等。请注意,在此过程的后期,最初的高级设计不仅会分解为更小,更精细的细节,而且我们很有可能会发现它存在缺陷,并且会进行更改以适应产品的需求。
- 一旦选择了要处理的易于管理的作品,我们可能必须为该作品创建详细的设计。这是通常通过编码进行设计的地方。我们知道要渲染3D世界,但不知道需要做什么。因此,我们编写了一个原型来渲染单个3D场景。然后创建一个静态场景。然后,我们查看所拥有的内容并思考-"好,接下来要做什么?我需要什么来使其对FPS游戏有用?我需要渲染很多不同的场景。好吧,这花了很多时间" "代码中的当前场景,如何使在当前场景上的变体更容易?如何创建一个全新的场景?如何存储场景描述?图形文件?声音文件?这是这里有人说过的话(引用XP的编程方式)的体现-我们不必先编写通用的复杂框架,而是编写所需的内容,但是一旦我们不得不再次编写具有相同变体的相同代码(渲染第二个场景,在当前场景上进行变化等),这就是我们泛化和增强框架的时候。
- 不要害怕编写扔掉的原型,这些原型将突出我们在设计中需要考虑的不同方面。这样一来,我们便有了具体的实现方法,可以以此为基础进行思考。
- 同样,在这里引用一些内容-不要冻结设计!这只是愚蠢的-如果我们意识到自己在设计中犯了一个错误,请重构以进行更改。只是要确保不要犯丢掉一切并从头开始的错误。通过重构进行增量更改通常效果更好。
最后但最重要的一点是,在这里我没有提出任何特别的或者革命性的东西,所有这些想法都是业内其他人概述的,比我聪明得多,也更有经验。我建议我们阅读一些有关"极限编程",Scrum和其他敏捷方法的知识,以及有关"实用程序员","代码完成","重构","四人帮"之类的通用书籍( aka"设计模式:可重用的面向对象软件的元素")...
希望所有这些文字对我们有所帮助:)
回答
从完整的设计角度一直到编码设计,我都有丰富的经验。这是我试图描述我对该主题的个人看法:
需求是开发中最重要,最重要的部分。在商业世界中,这份文件定义了可交付成果,是我们合法地需要给客户并获得报酬的法律。对于我们自己的个人项目,在这里我们可以取出一张纸并写下项目目标,然后从该目标中找出要求。
如果我们有良好的要求,并且可以避免一时兴起地更改要求,那么我们可以在此寻求基于餐巾纸的设计。仔细考虑我们要编写的代码,然后在纸上画出来,这可以仔细考虑几种可能性,并且可以以后编写更好的代码,因为我们已经做了一些思考。如果需求有所变化,请尝试将其修改为新版本。
开始编写代码,编写测试,并在代码中保留良好的注释。当我们从应用程序的另一个模块或者部分开始时,请花几分钟的时间仔细考虑该部分的总体设计,在餐巾纸设计和代码之间来回走动。接受在开始应用程序的另一部分并采用迭代方法进行开发之前,我们必须更改和修改所有我们认为完美的东西。
如果这是我学到的一件事,那么任何设计文档都总是过时的,而我们最终还是要看代码,因此,保留良好的注释非常有价值。我认为对于保持最新和可靠至关重要的唯一文档是要求和任何API参考(如果有的话)。