There's a principle called "do one thing and do it well" which may be related.
There's also the distinction between "pure function" (also called a "computation" or "calculation"), versus an "effectful procedure" (also called an "instruction" or "statement"):
- A pure function only returns a result (that is its 'externally observable behaviour'). It may arrive at that result directly, or by calling other pure functions. Examples include performing arithmetic, branching on some data, constructing some new value, etc.
- An effectful procedure will change the system in some way. Examples include printing some output, communicating with some external system (e.g. a database), changing the value of some externally-visible variable, etc. If a function returns an uninformative result, like
void
in Java, that's a good indicator that it's performing an effect (since there's no other reason for such a function to exist!)
It is a good idea to do as much calculation as possible using pure functions, since it is almost always 'safe' to call a pure function from anywhere in our code, without affecting any external system or any other part of our program (modulo edge cases like overflowing the stack). In contrast, we must be careful to only perform effects when it is safe to do so; for example, imagine calling a function to calculate some number, and it happens to also close a network socket! Effects can also alter the way other parts of our program behave, e.g. assigning a new value to a variable might alter the branches taken elsewhere in the code.
If a function/method does both of these things, i.e. performing some effects and returning some calculated result, it is said to be "impure". Such effects are called "side effects", since we may just want to do the calculation, but end up causing unintended effects as well.
This distinction appears in approaches like "ports and adapters"/"functional core, imperative shell"/"hexagonal architecture" and "pure functional programming".