你如何防止课程成为“依赖磁铁”和上课?

时间:2022-09-25 10:28:31

In virtually every project I've ever worked on, there will be one or two classes with the following properties:

在我曾经工作过的几乎每个项目中,都会有一两个具有以下属性的类:

  • Extremely large with many many members and methods.
  • 非常大,有许多成员和方法。

  • Many other classes inheriting from this class.
  • 从这个类继承的许多其他类。

  • Many other classes otherwise depending on this class.
  • 许多其他课程,否则取决于这个类。

Bad design, you might say. But in all cases, this wasn't the case at design time. The classes just grew organically over time and became the proverbial 'God class'. This has been such an invariant of my experience with large software projects that I have to ask:

你可能会说糟糕的设计。但在所有情况下,在设计时并非如此。这些课程随着时间的推移有机地成长,成为众所周知的“上帝阶级”。这对我在大型软件项目中的经验是如此不变,我不得不问:

  • Is it possible to foresee likely dependency magnets and design software in such a way that the chance of such classes manifesting themselves is less likely? If so, specifically, how?
  • 是否有可能以这样一种方式预见可能的依赖磁铁和设计软件,以至于这种类别表现出来的可能性较小?如果是这样,具体怎么样?

  • Or, does it simply require ruthless refactoring as time goes by?
  • 或者,随着时间的推移,它是否只需要无情的重构?

  • Or, is there some technical solution or design pattern which can mitigate the problems caused by such classes?
  • 或者,是否有一些技术解决方案或设计模式可以缓解这些类引起的问题?

  • Or, a combination of all three?
  • 或者,这三者的组合?

Tips, experience and ideas welcomed!

提示,经验和想法欢迎!

5 个解决方案

#1


Continually refactoring will help prevent this.

持续重构将有助于防止这种情况发生。

In addition, this is one place where forcing some amount of static code analysis can be very beneficial. You can often find these classes and flag them to refactor automatically very easily by looking at code metrics.

此外,这是一个强制进行一些静态代码分析的地方。您通常可以通过查看代码度量标准找到这些类并标记它们以便自动重构。

My biggest suggestion, though, is to keep a attitude that designs need to change, and things need to be broken apart. Often, in my experience, these classes form because people are unwilling to consider changing a broken or suboptimal design. Staying flexible makes it easier to prevent this.

不过,我最大的建议是保持设计需要改变的态度,事情需要分解。通常,根据我的经验,这些课程的形成是因为人们不愿意考虑改变破损或次优的设计。保持灵活性可以更容易地防止这种情况发生。

#2


A lot of this, I think, tends to stem from subsequent design laziness. The philosophy of "aggressive refactoring" is a very good antidote to this sort of design problem. The issue is that while the initial design for the 'dependency magnet' classes is good, subsequent time-stressed engineers tend to simply attach other functionality to that class for the simple reason that it's available where they need it (usually).

我认为,很多这种情况往往源于随后的设计懒惰。 “积极重构”的理念是解决这类设计问题的一个很好的解决方案。问题在于,虽然“依赖磁铁”类的初始设计是好的,但后续时间紧迫的工程师倾向于简单地将其他功能附加到该类,原因很简单,因为它可以在需要的地方(通常)使用。

Largely, the problem has to do with the fact that a design that can handle the needs of a mature software product is an overdesign for a less-mature software product. All of the design that ends up being in a mature iteration of a software product is massive overkill for an earlier iteration of that product; fundamentally, the design must always be fiddled with as development continues, therefore. And this is where the refactoring is necessary; as new features and functionality begin to be implemented, design problems will show their heads; as they do, it's critically important to take on the task of redesigning the way in which the classes interact, and to refactor the code to take advantage of it. Only in that way can you maintain a design maturity that is in any type of similarity with the project maturity.

很大程度上,问题与这样一个事实有关:能够处理成熟软件产品需求的设计是对不太成熟的软件产品的过度设计。所有最终都在软件产品的成熟迭代中的设计对于该产品的早期迭代来说是大量的过度杀伤;从根本上说,随着开发的继续,设计必须始终摆弄。这就是重构是必要的;随着新特性和功能开始实施,设计问题将显示出来;正如他们所做的那样,承担重新设计类交互方式的任务以及重构代码以利用它的任务至关重要。只有这样,才能保持与项目成熟度具有任何相似性的设计成熟度。

Effectively, there is a level of design maturity that increases along with the project complexity; a massively complex design for a simple project is inappropriate; in the same way that a massively simple design for a complex project is inappropriate. But because that mismatch exists, the design must evolve along with the project. Refactoring as a process is simply a recognition of that necessity.

实际上,设计成熟度会随着项目的复杂性而增加;对于简单的项目而言,大型复杂的设计是不合适的;就像复杂项目的大规模简单设计是不合适的一样。但由于存在不匹配,设计必须随项目一起发展。重构作为一个过程只是对这种必要性的认识。

#3


This one:

  • Many other classes inheriting from this class
  • 从这个类继承的许多其他类

can be overcome by preferring composition over inheritance.

可以通过优先考虑组合而不是继承来克服。

#4


My experience is that the first design you come up isn't usually right and over time you need to rethink the design. When a class starts to get too large it is usually because it starts to violate SRP.

我的经验是,您提出的第一个设计通常不正确,随着时间的推移,您需要重新考虑设计。当一个类开始变得太大时,通常是因为它开始违反SRP。

Some of Fowler's refactoring patterns are useful. The Extract Class refactoring can help, as can Extract Subclass and Extract Superclass. I often find myself changing inheritance hierarchies, perhaps using replace inheritance with delegation.

福勒的一些重构模式很有用。 Extract Class重构可以提供帮助,Extract Subclass和Extract Superclass也可以提供帮助。我经常发现自己正在改变继承层次结构,也许使用替换继承和委托。

#5


Ruthless refactoring for me too, especially for small (i.e. not highly-designed, waterfall) projects which last a long time (e.g. years).

对我来说也是无情的重构,特别是对于持续很长时间(例如几年)的小型(即不是高度设计的瀑布)项目。

I start small: a little bit of architecture, say 2 to 5 components. I implement functionality by adding code to these components ... and when a component gets too big (which is subjective) then I divide it into more than one component. [By 'component' I mean 'package' or 'DLL' or something.]

我从小开始:一点点架构,比如2到5个组件。我通过向这些组件添加代码来实现功能......当组件变得太大(这是主观的)时,我将它分成多个组件。 [''component'我的意思是'包'或'DLL'之类的东西。

"Dependency magnets" is a slightly different problem: to address that, I'm keen on layering software, without cyclic dependencies between layers, and sometimes with a facade which insulates high-level from low-level components.

“依赖磁铁”是一个稍微不同的问题:为了解决这个问题,我热衷于分层软件,没有层之间的循环依赖关系,有时还有一个外观,它将高级别与低级别组件隔离开来。

#1


Continually refactoring will help prevent this.

持续重构将有助于防止这种情况发生。

In addition, this is one place where forcing some amount of static code analysis can be very beneficial. You can often find these classes and flag them to refactor automatically very easily by looking at code metrics.

此外,这是一个强制进行一些静态代码分析的地方。您通常可以通过查看代码度量标准找到这些类并标记它们以便自动重构。

My biggest suggestion, though, is to keep a attitude that designs need to change, and things need to be broken apart. Often, in my experience, these classes form because people are unwilling to consider changing a broken or suboptimal design. Staying flexible makes it easier to prevent this.

不过,我最大的建议是保持设计需要改变的态度,事情需要分解。通常,根据我的经验,这些课程的形成是因为人们不愿意考虑改变破损或次优的设计。保持灵活性可以更容易地防止这种情况发生。

#2


A lot of this, I think, tends to stem from subsequent design laziness. The philosophy of "aggressive refactoring" is a very good antidote to this sort of design problem. The issue is that while the initial design for the 'dependency magnet' classes is good, subsequent time-stressed engineers tend to simply attach other functionality to that class for the simple reason that it's available where they need it (usually).

我认为,很多这种情况往往源于随后的设计懒惰。 “积极重构”的理念是解决这类设计问题的一个很好的解决方案。问题在于,虽然“依赖磁铁”类的初始设计是好的,但后续时间紧迫的工程师倾向于简单地将其他功能附加到该类,原因很简单,因为它可以在需要的地方(通常)使用。

Largely, the problem has to do with the fact that a design that can handle the needs of a mature software product is an overdesign for a less-mature software product. All of the design that ends up being in a mature iteration of a software product is massive overkill for an earlier iteration of that product; fundamentally, the design must always be fiddled with as development continues, therefore. And this is where the refactoring is necessary; as new features and functionality begin to be implemented, design problems will show their heads; as they do, it's critically important to take on the task of redesigning the way in which the classes interact, and to refactor the code to take advantage of it. Only in that way can you maintain a design maturity that is in any type of similarity with the project maturity.

很大程度上,问题与这样一个事实有关:能够处理成熟软件产品需求的设计是对不太成熟的软件产品的过度设计。所有最终都在软件产品的成熟迭代中的设计对于该产品的早期迭代来说是大量的过度杀伤;从根本上说,随着开发的继续,设计必须始终摆弄。这就是重构是必要的;随着新特性和功能开始实施,设计问题将显示出来;正如他们所做的那样,承担重新设计类交互方式的任务以及重构代码以利用它的任务至关重要。只有这样,才能保持与项目成熟度具有任何相似性的设计成熟度。

Effectively, there is a level of design maturity that increases along with the project complexity; a massively complex design for a simple project is inappropriate; in the same way that a massively simple design for a complex project is inappropriate. But because that mismatch exists, the design must evolve along with the project. Refactoring as a process is simply a recognition of that necessity.

实际上,设计成熟度会随着项目的复杂性而增加;对于简单的项目而言,大型复杂的设计是不合适的;就像复杂项目的大规模简单设计是不合适的一样。但由于存在不匹配,设计必须随项目一起发展。重构作为一个过程只是对这种必要性的认识。

#3


This one:

  • Many other classes inheriting from this class
  • 从这个类继承的许多其他类

can be overcome by preferring composition over inheritance.

可以通过优先考虑组合而不是继承来克服。

#4


My experience is that the first design you come up isn't usually right and over time you need to rethink the design. When a class starts to get too large it is usually because it starts to violate SRP.

我的经验是,您提出的第一个设计通常不正确,随着时间的推移,您需要重新考虑设计。当一个类开始变得太大时,通常是因为它开始违反SRP。

Some of Fowler's refactoring patterns are useful. The Extract Class refactoring can help, as can Extract Subclass and Extract Superclass. I often find myself changing inheritance hierarchies, perhaps using replace inheritance with delegation.

福勒的一些重构模式很有用。 Extract Class重构可以提供帮助,Extract Subclass和Extract Superclass也可以提供帮助。我经常发现自己正在改变继承层次结构,也许使用替换继承和委托。

#5


Ruthless refactoring for me too, especially for small (i.e. not highly-designed, waterfall) projects which last a long time (e.g. years).

对我来说也是无情的重构,特别是对于持续很长时间(例如几年)的小型(即不是高度设计的瀑布)项目。

I start small: a little bit of architecture, say 2 to 5 components. I implement functionality by adding code to these components ... and when a component gets too big (which is subjective) then I divide it into more than one component. [By 'component' I mean 'package' or 'DLL' or something.]

我从小开始:一点点架构,比如2到5个组件。我通过向这些组件添加代码来实现功能......当组件变得太大(这是主观的)时,我将它分成多个组件。 [''component'我的意思是'包'或'DLL'之类的东西。

"Dependency magnets" is a slightly different problem: to address that, I'm keen on layering software, without cyclic dependencies between layers, and sometimes with a facade which insulates high-level from low-level components.

“依赖磁铁”是一个稍微不同的问题:为了解决这个问题,我热衷于分层软件,没有层之间的循环依赖关系,有时还有一个外观,它将高级别与低级别组件隔离开来。