Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you prevent classes becoming 'dependency magnets' and God classes? [closed]

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!

like image 482
maxaposteriori Avatar asked May 22 '09 21:05

maxaposteriori


2 Answers

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.

like image 122
Reed Copsey Avatar answered Oct 04 '22 19:10

Reed Copsey


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.

like image 37
Paul Sonier Avatar answered Oct 04 '22 20:10

Paul Sonier