4

A class is too large and becomes unwieldy to work with. In Objective-C I'd be tempted to use Categories to break the class up, but then: wouldn't categories just be dividing a house full of too much junk into rooms? The same question applies to partial classes in C#, I suppose.

Under what conditions can categories be used to solve a "class too large" code smell? When is it not correct and the class really needs to "be restructured or broken into smaller classes?"

James A Mohler
  • 11,060
  • 15
  • 46
  • 72
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421

4 Answers4

9

A very good principle to refer to is the SOLID principle. In particular the "S" stands for "Single responsibility"

Single responsibility principle

the notion that an object should have only a single responsibility.

When classes get too big, it is likely they have too many responsibilities. Can you define two or more responsibilities within the boundaries of what the class is doing? If so, separate it into two, or more, classes. You can then aggregate them back using a façade or composite pattern.

In other words:

  • the code you have in the class should be split in different classes according to the Single Responsibility principle
  • the original God class becomes a composite or façade: it uses all the new classes, exposes the same methods to the rest of the system, but does not implement any functionality in itself, besides "converting" the old-style god-class calls in the new-style SOLID calls.

This means that regions do exactly nothing to solve your problem, from an object-oriented point of view. In fact, they are actually counterproductive as they contribute to hiding the problem.

See also this Jeff Atwood article:

http://www.codinghorror.com/blog/2008/07/the-problem-with-code-folding.html

CodingHorror-regions
(source: typepad.com)

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Sklivvz
  • 30,601
  • 24
  • 116
  • 172
  • Assuming that the different responsibilities of the God class are never used individually, why prefer Facade or Composite when *partial* classes -- divided by responsibility, of course -- do the same thing? – Dan Rosenstark Nov 05 '11 at 15:31
  • 1
    Because you want your code to be object oriented :-) God classes are procedural, and "partial" classes are just classes. It's syntactic sugar to allow you to split the source over more files. For more info on why one wants to be object oriented, see e.g. http://eprints.ecs.soton.ac.uk/857/3/html/node3.html – Sklivvz Nov 05 '11 at 16:34
  • For my own notes: this answer is still correct, or course. MANY times, though, the solution to a giant, persistent object is not breaking it up into several smaller objects in a 1->1->1-> relationship (Facade and Composite are like this, often). In fact, this is the same as using Categories (or Partial classes)...just hides the problem. The answer lies in creating objects dynamically that hold both data and behavior. No doubt there are several design patterns -- like ValueObject -- that explain what I'm trying to say better than I have. – Dan Rosenstark Nov 14 '14 at 16:29
  • Composition and the composite pattern are two radically different things. The former is simply the direct use of other classes as non-static members, while the latter enables arbitrarily deep trees of objects sharing a common supertype to be constructed and used. You should read the wikipedia page you linked to your answer (... that is, if you still haven't done it by now lol). – ljleb Feb 08 '22 at 11:52
2

I must admit I never used Objective-C, but of course, I used C#.

Said this, partial classes are the same thing that classes, splitting a class into multiple files doesn't make the class smaller, only splitted in file. The usage of the class will be the same.

So I don't agree partial classes will solve that problem, they were invented mostly for other things, like, windows forms, wpf, autogenerated code. They are useful also in other situations where classes cannot be logically splitted, but usually, should be avoided.

I think you should divide your class in several classes, a class starts to smell after 1k LOC (lines of code), also if the class is splitted in multiple files.

Use inheritance or split the class in several classes connected by fields and properties. In the example provided by chemicalNova i would split that in several classes, not in several files.

Salvatore Previti
  • 8,956
  • 31
  • 37
  • 1
    While I agree.. classes can get this big, even in enterprise solutions. We can try as hard as we can, but not all of our code is consistently the calibre of a "Patterns and Practices" book. Sometimes splitting into several classes requires rewrites of an entire application.. which sometimes isn't practical. – chemicalNova Nov 05 '11 at 10:24
  • 1
    I'm the first to say that pattern programming should not be followed as an absolutist religion or as the ultimate truth: there are cases and cases. However allowing things like a God class is pure evil :) – Salvatore Previti Nov 05 '11 at 14:37
1

I remember when I was a novice, we had this god class "BusinessService", or something similar. Anytime someone had locked it in TFS, you were left out of luck. So I had this brilliant idea, why don't we split it into partial classes. We ended up with something like "BusinessService1.cs" .. "BusinessService6.cs". It was a complete mess, and a complete frustration to find where things are.

I think every time you need to use partial class, it is a design mistake. If Microsoft forces you to do so (wpf, winforms, etc) - it's their design mistake.

driushkin
  • 3,531
  • 1
  • 24
  • 25
  • There are some excellent reasons to use partial classes in relation to generated code. You prefer the old #Region method? – Andrew Barber Nov 05 '11 at 08:46
  • Partial classes are not a mistake, thanks microsoft that invented that :) but as I said, their are useful mostly just with autogenerated code. – Salvatore Previti Nov 05 '11 at 09:20
  • In my opinion, partial classes are almost the same thing as regions. Yes there are some technical differences between them. But they are solution to the same problem which shouldn't be there in the first place. – driushkin Nov 05 '11 at 12:00
  • I generally agree with you, aside from cases of code generation. (see my comments to chemicalNova's answer) – Andrew Barber Nov 06 '11 at 00:52
-2

Theres nothing wrong with splitting a class into partials. Its something that few developers take advantage of.

Personally, I like to split larger classes into partials where the business side of things for each partial have similar functionality - but only if during design time it looks like said class will become quite big. Otherwise, I split related functionality into region's.

As an example, if I am to have a "UserService" that is within a data layer, I might split it into several partials like so:

UserServiceQueries.cs
UserServiceUpdates.cs
UserServiceInserts.cs
UserServiceLogicalFunctions.cs

..however, they contain partial classes of "UserService". I don't usually use ORM's a lot, so this is perfect for me because each piece of related functionality can become quite large (obviously this is a basic example).

In closing: take advantage of what is supplied. If you're getting code smell from your class being huge.. you've only got 2 choices.. re-write it, or split it up (if it definitely needs to be this large).

My opinion anyway.

chemicalNova
  • 831
  • 5
  • 12
  • 2
    You are fooling yourself if you think partials classes are "splitting" anything at all but your source code. You still have a God Class... it's just split into more files. If you are creating partials that aren't related to code generation, you're probably doing something wrong. – Andrew Barber Nov 05 '11 at 08:48
  • At no point did I say anything other than that its splitting the code. Fact is, sometimes classes do get this big. I just explained a way that I, personally, split related code from large "God" classes so they are easier to follow. – chemicalNova Nov 05 '11 at 10:14
  • and I just gave my opinion on that practice. It ends up *not* making things easier at all... you still have one giant class, but now you can't even find all its code in one place. A worse situation in every possible way. *In my opinion*... – Andrew Barber Nov 06 '11 at 00:50
  • I completely disagree, @Andrew. We routinely split our classes into the main code, then a partial for all of our command definitions and handlers of those definitions including the set-up of those commands in an InitializeCommands function. This way, we know if, and only if it's related to commands it's in the latter file whereas the class 'body' itself is in the main file. Plus, this also allows two people to work on the same class without walking on each other: one person can wire up the UI code while the other writes the implementation. Very clean and efficient with no 'smell' at all. – Mark A. Donohoe Feb 03 '13 at 09:46
  • Another case where we use it is if our class explicitly implements a large interface which simply delegates down to existing methods on the main class. For instance, say we have a class called 'Foo' with a property 'Count'. 'Foo' implements 'ILaa' which has a 'GetCount' property. We move the entire implementation of 'ILaa' (mostly boiler-plate code) over to 'Foo.ILaa.cs' and leave 'Foo.cs' to the actual implementation of 'Foo'. If it's a smaller interface, we put it in a region within 'Foo.cs', something else that is effective when used properly regardless of what 'Joe Code Horror' says. – Mark A. Donohoe Feb 03 '13 at 09:57
  • @MarqueIV I was specifically referring to chemicalNova's answer, as it relates to the question posed; That is, whether it is a good idea to split a "God Class" into partials. Your use is clearly different; It's not to artificially make a God Class seem simpler - it's to organize code that does not otherwise smell (or for which you have no choice) – Andrew Barber Feb 04 '13 at 18:39
  • No worries, @Andrew. Was concerned this was a case of 'Regions are evil' and 'Partial Classes are lazy' thoughts, period. Usually I agree with most things Jeff Atwood (Coding Horror) says, but this to me is just something that he (and others) draw a hard line in the sand and it's not justified. It's not automatically code smell to use those features as they say. There are cases where it makes sense, especially when making it a pattern of your development like we have. In context, you have a point. Just making sure the absolute-black/blinding-white view wasn't taken. – Mark A. Donohoe Feb 06 '13 at 09:52