• HOME
  • ABOUT US
  • SERVICES
  • PORTFOLIO
  • BLOG
Connection Quest Connection Quest
  • HOME
  • ABOUT US
  • SERVICES
  • PORTFOLIO
  • BLOG
Connection Quest

Decompose!

Home / Clean C++ / Decompose!

Decompose!

By Marko Jovic inClean C++

Functions exist so we can meaningfully package related operations into reusable entities. And so we should.

But first things first. A function should perform a single logical operation (one thing). Consequently, it should be short. If a function does more than one thing, split it up.

void logAndPrintData() {
	// two things
}
void logData() {
	// one thing
}
void printData() {
	// one thing
}

Keep your functions up to 20 lines long. This mandates the following:

  • conditional / loop statement blocks should be one line long
  • a function should have only one or two indent levels

By doing this, your functions become transparently obvious and trivially easy to change. Furthermore, if you can achieve the newspaper metaphor, as shown in our previous post, then each function naturally leads on to the next.

As stated, a function should perform a single logical operation. It should comprise of steps that are one abstraction level lower than the function name, which you can see in the following example:

void connect() {
	getDevice();
	setupConnectionParameters();
	connectToDevice();
}

What’s more, a function should do exactly what it specifies to do. It should have no side effects.

void addNumbers(int &a, int &b) {
	c = a + b;
	a = -1;  // this is a side effect
}

In the example above, a change to the variable a is a side effect, which the function does not state to do. Side effects often create unnecessary coupling and dependencies.

Try to separate commands from queries. A function should either change the state of an object, or return some information about it, not both.

Of course, you should always strive to eliminate duplication and to stay DRY (Don’t Repeat Yourself). When functions perform conceptually the same task on different types, use overloading.

In the unfortunate event of an error (impossible, I know), prefer exceptions to returning error codes. Extract try / catch blocks into functions of their own and separate error handling from the processing code.

void updateFile() {
    readFile();
    process();
    writeFile();
}

void process() {
    try {
        ...
    } catch () {
        ...
    }
}

If a function may have to be evaluated at compile time, introduce performance improvements by declaring it constexpr (C++ 11).

constexpr int multiply(int a, int b) {
	return a * b;
}

One of the most important features of a function is the ability to have parameters. However, you should write functions with as little parameters as possible. Fewer parameters means fewer special conditions to check as well as fewer things for the function to do. Try to adhere to the following:

  • if you find yourself passing a lot of arguments, convert them into class members.
  • don’t use output arguments, let the function change the state of its owning object
  • don’t use flag arguments, they make the function do more than one thing
  • use functions with multiple arguments only when arguments are ordered components of a single value
    • Point makePoint(x, y, z)
  • use argument lists freely, they count as one argument
    • String outputNumbers(Integer… numbers)

By decomposing our monolithic code blocks into functions we achieve greater readability and maintainability. If you go a step further and name your functions carefully, you’ll even effectively document your code.

Stay tuned and happy coding.

AdviceC++Clean CodeConventionsDecompositionFunctionsSoftwareSoftware Development
15 Posts
Marko Jovic
  • Work out your types
    Previous PostWork out your types
  • Next PostObjects vs. Data Structures
    Work out your types

Leave a Reply (Cancel reply)

Your email address will not be published. Required fields are marked *

*
*

© 2025 Connection Quest j.d.o.o. All rights reserved.

Copy