哪些更改太大而无法通过适当的设计轻松实现?


11

这是一个相当模糊的问题,但这是我在阅读有关适当设计的内容时从未感到满意的答案。

通常,在学习面向对象的编程,抽象,分解等方法时,设计的圣杯以及它们始终声称您使用的是开发技术的原因是,这将使您的程序“易于更改” ,“可维护的”,“灵活的”或用于表达这种有效果的概念的任何同义词。通过将ivars标记为私有,将代码拆分为许多小的自包含方法,使接口保持通用,可以使您完全轻松自如地修改程序。

对于较小的更改,这对我来说效果很好。改变类以提高性能所用的内部数据结构从来都不是主要困难,而且独立于API的用户界面端也没有改变,例如重新设计文本输入系统或检修游戏元素的图形。

所有这些更改似乎天生就是独立的。就所涉及的外部代码而言,它们均不涉及对要修改的程序组件的行为或设计进行任何更改。无论您是以程序编写还是以OO样式编写(具有大型功能还是小型功能),即使您只有中等程度的设计,也可以轻松进行这些更改。

但是,每当更改变得繁琐而繁琐时(即,对API进行更改),我的所有宝贵“模式”都无法挽救。巨大的变化仍然很大,受影响的代码仍然受到影响,并且大量的错误产生工作摆在我面前。

所以,我的问题是这个。适当的设计声称能够促进多大的变化?是否有一些其他的设计技术,或者对我来说是未知的,或者是我没有实现,确实确实使粘滞性修改变得简单,还是那个承诺(我听说过这么多不同的范例)仅仅是一个好主意,完全脱离了软件开发的一成不变的真理?我可以添加到工具栏中的“更改工具”吗?

具体来说,导致我进入论坛的问题是:我一直在努力实现一种解释性编程语言(在D中实现,但这无关紧要),并且我决定将闭包的参数设为基于关键字,而不是当前的位置。这就需要修改所有现有的调用匿名函数的代码,幸运的是,这很小,因为我很早就开发了我的语言(<2000行),但是如果我稍后再做出决定,那将是巨大的。在这种情况下,是否可以通过适当的预见性设计使修改变得更容易,或者确定(大多数)变化本质上影响深远?我很好奇这是否是我自己的设计技能的失败-如果是的话,我

明确地说,我绝不怀疑OOP或其他常用的模式。但是,对我而言,它们的优点在于代码库的原始编写而不是维护。继承使您可以很好地抽象出重复的模式,多态性使您可以通过人类理解的函数(哪个类)而不是由机器理解的效果(switch语句的哪个分支)来分离代码,而小的独立函数可以让您以一种非常愉快的“自下而上”的风格写作。但是,我对他们的灵活性表示怀疑。


除了解析器,我看不到您的语言更改如何影响其他内容。你能澄清一下吗?
Scarridge

在类似Smalltalk的语言中,确实只需要修改解析器,这是事实,因为将foo metarg1: bar metarg2: bazas视为一个简单的问题foo.metarg1_metarg2_(bar, baz)。但是,我的语言正在进行较大的更改,即将基于列表的参数更改为基于字典的参数,这实际上会影响运行时,但不会影响解析器,实际上,由于我的语言的特定属性,我现在不再讨论。由于在无序关键字和位置参数之间没有明确的映射,因此运行时是主要问题。
存在

Answers:


13

有时,更改足够大,您必须设计迁移路径。即使起点和终点设计合理,您通常也不能只换成冷火鸡。许多本来不错的设计师都没有设计好的移植路径。

这就是为什么我认为每个程序员都应该为24/7生产环境做一个临时编写软件的原因。每分钟的年薪顺序会列出一些损失,这会激发您学习编写健壮的迁移代码的动机。

人们自然而然地会做一个大的改变,那就是淘汰旧方法,改用新方法,然后花几天的时间修复不计其数的编译错误,直到您的代码最终再次被编译,以便您可以开始测试。由于该代码两天都无法测试,因此突然有大量纠缠的错误需要解决。

对于较大的设计更改(例如从位置参数更改为关键字),一个好的移植路径是首先添加对关键字参数的支持,而无需删除位置支持。然后,您有条不紊地更改调用代码以使用关键字参数。这与您之前的操作类似,但是这次您可以继续进行测试,因为未更改的调用代码仍然有效。由于您在测试之间所做的更改较小,因此这些错误更容易在早期修复。然后,当所有调用代码都已更改时,删除位置支持很简单。

这就是为什么公开发布的API弃用旧方法而不是删除旧方法的原因。它为调用代码提供了无缝的迁移路径。同时支持这两者可能需要更多的工作,但是您却浪费了测试时间。

因此,按照最初的措辞来回答您的问题,几乎没有太大的变化,以至于通过适当的设计使其变得不那么容易。如果更改看起来太大,则只需要设计一些临时的中间阶段即可迁移代码。


+1支持新案例和旧案例,因此您可以随时删除。
Erik Reppen

9

我建议您阅读泥浆大球文章。

基本上,随着开发的进行,设计趋于恶化,这时您就必须致力于解决复杂性问题。复杂性本身无法消除,只能消除,因为它是您要解决的问题所固有的。

这导致了敏捷开发的主要原则。最相关的两个是“您将不需要它”,告诉您不要为尚未实现的功能准备设计,因为无论如何您都不可能正确地设计,并且“毫不留情地重构”告诉您工作在整个项目中保持代码的完整性。

似乎答案是,除了专门设计用来表明设计比实际更坚固的示例之外,没有任何设计能够促进任何更改。

附带说明一下,您应该对面向对象编程持怀疑态度。在许多情况下,它是一个很棒的工具,但是您需要意识到它的局限性。尤其是滥用继承会导致一些令人难以置信的复杂代码。当然,您应该同样怀疑其他任何设计技术。每个都有其用途,每个都有其弱点。没有银弹。


1
+1:新颖的前期设计很少成功。成功的设计要么是对经过验证的设计的概括,要么是经过反复完善。
凯文·克莱恩

1
+1您应该对所有编程概念都持怀疑态度,只有通过客观的批评,我们才能运用我们的分析能力找到正确的解决方案,而不仅仅是找到解决方案
Jimmy Hoffa 2013年

4

一般而言,有“代码段”(函数,方法,对象等)和“代码段之间的接口”(API,函数声明等;包括行为)。

如果可以在不更改其他代码所依赖的接口的情况下更改一段代码,那么更改将更加容易(并且无论是否使用OOP都无关紧要)。

如果在不更改其他代码所依赖的接口的情况下无法更改某段代码,那么更改将变得更加困难(无论是否使用OOP,这都没有关系)。

OOP的主要好处是可以清楚地标记公共“接口”(例如,对象的公共方法),而其他代码则不能使用内部接口(例如,对象的私有方法)。因为公共接口有明显的标记,所以人们倾向于更加谨慎地设计那些公共接口(这有助于避免更困难的更改)。因为其他代码不能使用内部接口,所以您可以更改它们而不必担心依赖于它们的其他代码。


OOP的另一个优点是,使用对其进行操作的逻辑封装数据会导致较小的公共接口(如果做得好)。
Michael Borgwardt

2

没有一种设计方法可以使您摆脱繁琐的需求/范围变更的麻烦。根本无法想象和解释以后可能想到的所有可能的更改。

好的设计您有所帮助的地方是帮助您了解所有零件的装配方式以及所建议的更改将影响什么。
此外,良好的设计可以限制受大多数建议的更改影响的零件。

简而言之,好的设计可以使所有更改变得容易,但是好的设计不能将大的更改变成小更改。(另一方面,不好的设计/没有的设计可以将任何小的更改变成大的更改。)


1

由于设计的目的是将一个开发项目从零白纸变成一个可靠的最终产品(至少是针对一个产品的设计),而这是对项目的最大改变,我怀疑是否有这样的事情:太大而无法处理的变化。

如果有的话是相反的。有些更改太小了,无法打扰任何“设计”或花哨的思维。例如,简单的错误修复。

请记住,设计模式是为了帮助清晰思考并找到针对常见情况的好的设计解决方案,例如创建大量的小型相同类型的对象。模式列表不完整。您和我们所有人都会遇到一些不常见的设计问题,这些问题将无法解决。尝试按照一种或另一种官方模式在软件开发过程中采取任何小动作,是一种过分虔诚的做事方式,并导致无法维持的混乱局面。

软件中的所有工作自然都是错误产生的。足球运动员受伤。音乐家会根据自己的乐器而出现老茧或唇痉挛。(如果弹吉他时出现唇部痉挛,说明您做错了。)软件开发人员会遇到错误。我们喜欢找到降低它们产卵率的方法,但是永远不会为零。


3
起始位置也可以为负。不要小看遗产的力量:)
Maglob

从零开始设计项目很容易。但是,即使您是从头开始的新项目(这本身并不多见),您也只会在头几天享受从无到有的构建。比最初的最初设计决策被证明是错误的,事情只会从那里开始下坡。从零开始的设计在实践中是完全不相关的。
Jan Hudec

1

全面更改的成本通常与代码库的大小成正比。因此,减少代码库的大小应该始终是任何适当设计的目标之一。

在您的示例中,正确的设计已经使您的工作更加轻松:必须在整个2000行代码库中进行更改,而不是在20000或200000行代码库中进行更改。

适当的设计可以减少较大的变化,但不能消除它们。

如果语言分析工具提供了适当的支持,则可以轻松轻松地完成所有更改。一揽子重构更改可以搜索和替换的方式应用于整个代码库(同时适当遵守语言规则)。程序员只需为每个搜索命中做出是/否判断。


+1为自动化建议。我想我实际上会在很多调用闭包的库函数中使用它-这是一个简单的问题,即检测哪些函数带有块并对其进行修改以使参数名称具有额外的符号参数,以将值传递为。
存在于2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.