3

The golden rule of code structuring is always said as splitting into many sub functions is a good thing. Though I noticed it becomes a problem in complex applications when a class of e.g. 10 bigger functions is split into a class with 50 functions. When development went so far, it becomes quite hard to understand the concept of the class, I mean you lose survey. This is often the case when you look into code of others or in your own code after some months past.

I've heard a function should not be bigger than what fits on the screen. And then you start to split into sub functions, and the following effect is a class of many functions where you lose survey.

One example: The Qt library internally uses private classes, which means every class has a d pointer to a private object of its own private class containing all those helper functions moved out to it.

Sometimes I also wished I could colour the background of the important code.

So what's your approach of keeping complex code structured but still understandable?

  • How about splitting up your class into 5 classes with 10 small functions each? – Florian Margaine Jun 11 '13 at 08:56
  • @Florian Margaine: Good tip. And if you have too many classes in one module, split the module into several modules with at most 10 classes each. And if you have too many modules split your system into subsystems with at most 10 modules each. With subsystems, modules, classes, functions (i.e. 4 layers of abstraction) where each layer can contain at most 10 elements of the lower layer, you can have a system with 10^4 = 10000 functions. And, of course, each function should not have more than 10 lines (according to uncle Bob, no more than 4, 6 lines, but let's be generous). ;-) – Giorgio Jun 11 '13 at 09:24
  • I have a controller class of 3500 code lines written in C, and about 70 functions. The whole thing uses a struct containing the data it works on. How do you handle that shared data after the split? –  Jun 11 '13 at 09:31
  • @falkb: can't you pass the shared struct around using a pointer argument in the functions? – Giorgio Jun 11 '13 at 09:33
  • What if the shared struct was private in the original class, and now it must be spread around the new set of classes; how can you keep it still private from the rest of the system? –  Jun 11 '13 at 10:30
  • If keeping it private is making it difficult to refactor your class then don't keep it private. – Seth M. Jun 11 '13 at 11:24
  • @falkb: You should also ask yourself if the whole struct is needed by all the functions. Maybe you can split the struct into smaller structs? Otherwise, I agree with Seth M.: if you need to share data across different modules, then your data should not be private. – Giorgio Jun 11 '13 at 14:34
  • people who say "function should fit on one screen" are goofs. The appropriate length of any function is "as long as required do the work". One long function is not harder to read than 5 short functions. – DwB Jun 11 '13 at 18:25
  • @DwB: Readability is not the only factor: you should be able to keep what you read in your mind so that you can modify it safely. So the appropriate length is "as long as you can keep it in your mind at once", which might be more than one screen, of course. Otherwise, good luck maintaining your code. – Giorgio Jun 12 '13 at 06:18
  • see also: [Should I extract specific functionality into a function and why?](http://programmers.stackexchange.com/q/166884/31260) – gnat Mar 23 '15 at 11:35

3 Answers3

6

The canonical answer is to apply the Single Responsibility principle:

the single responsibility principle states that every class should have a single responsibility, and that responsibility should be entirely encapsulated by the class. All its services should be narrowly aligned with that responsibility.

Also, classes must have Cohesion

cohesion refers to the degree to which the elements of a module belong together. Thus, it is a measure of how strongly-related each piece of functionality expressed by the source code of a software module is

On the other hands, symptoms of low cohesion are exactly what you describe:

Disadvantages of low cohesion (or “weak cohesion”) are:

  • Increased difficulty in understanding modules.
  • Increased difficulty in maintaining a system, because logical changes in the domain affect multiple modules, and because changes in one module require changes in related modules.
  • Increased difficulty in reusing a module because most applications won’t need the random set of operations provided by a module.

As such, my advice is to review your class structure and refactor appropriately. You don't need to have very large classes, but certainly you want classes that do one clear thing right.

Sklivvz
  • 5,242
  • 19
  • 34
1

If you Feel Like it Could Be Splitted, Split It!

I don't really think of the balance as you seem to be considering it now: if it's bigger than 25 or 30 lines, and if I cannot get it almost instantly, then it can be refactored into smaller functions. Especially for big "torrent" functions that tend to be very imperatively written.

Use Descriptive Coding Conventions

Yes, the reader will need to jump through more hoops to understand the code, but if the functions are aptly named, it's an help. It's also an help if you get a stacktrace, as it gives you a semantic hint on what was happening.

Visual Aids

Sometimes I also wished I could colour the background of the important code.

Quite often, it's likely the "unimportant" code that's mostly internal and that you can separate into smaller functions can be put into private methods or extracted to utility classes.

While it has some disadvantages too (testing, coupling, etc...), it can help to quickly visually separate them from the rest, especially if you can change your code highlighting rules based on the access modifiers.

haylem
  • 28,856
  • 10
  • 103
  • 119
  • Do you know if and where I can set code highlighting rules (based on the access modifiers) in MSVC? I haven't found such settings. –  Jun 12 '13 at 08:43
  • @falkb: no idea, haven't used the thing in over 2 years, and I wouldn't have touched these settings. You definitely can in Eclipse for Java development (and I think for C++ development as well), but I never really tweaked my Visual Studio: preferred to keep it in a state where it wouldn't freak out others. – haylem Jun 12 '13 at 10:29
  • @falkb: see this [answer](http://stackoverflow.com/questions/115388/how-can-i-customize-the-syntax-highlighting-in-visual-studio-2005), maybe, for some more help. However I had a quick look and I don't think Visual Studio allows for this kind of customization without additional plugins. – haylem Jun 12 '13 at 11:04
0

So what's your approach of keeping complex code structured but still understandable?

My approach is to build several abstraction layers and have each component of each layer contain at most n elements from the lower layer, where n is a relatively small number (between 5 and 20) beyond which I lose the overview of the structure of a component. I cannot name an exact number but I would say 20 is already in the "too large" area for me. If you can keep more stuff in your mind, your number may be higher.

As an example, consider the 6 layers: system, subsystem, module, class, method, line of code. The names are chosen a bit arbitrarily, but it should give the idea. Also, let n = 10.

Take a module: it can have at most 10 classes (to be more flexible, let's say it can also have 12 or 15 classes, but definitely not 50 classes!). Apply the same principle to all layers: if a method has more than 10 lines it is doing too much, try to split it. If a class has more than 10 methods: split it. Etc.

With this scheme, you can organize roughly 10^5 = 100000 lines of code. Still, if you look down from a higher layer to a lower one, you still see some component that has at most 10 sub-items. If your project is larger, you can add extra abstraction layers.

The main idea is to split items that are too large to be understood and to push the complexity to the upper abstraction layers until you have enough abstraction layers to manage the complexity of the whole project.

Giorgio
  • 19,486
  • 16
  • 84
  • 135