Software Design/Don't repeat logic in several places

Checklist questions:
 * Can repeated logic be extracted into a function?
 * Can repeated logic be encapsulated in a wrapper (adapter) object?
 * Can design of an abstract class be changed to avoid logic repetition in the implementations or at the usage sites?

This practice reflects the Don't repeat yourself principle.

Why
The repeated logic will be a source of change amplification should it be changed in the future, thus making the code harder to change.

Logic repetition welcomes bugs via typing mistakes and forgetting to update some places in the code where the logic occurs when the latter needs to be changed.

Duplication means every time readers see these copies, they need to compare them carefully to see if there is any difference, thus contributing to the cognitive load.

A common byproduct of removing logic repetition is improving reusability of the code: if similar logic is already needed in several places in the codebase, it's quite likely that more such places will emerge in the future as the codebase grows. The abstractions that have been created to remove the logic repetition (see the next section) can then be reused in the new places.

Extract a function
When the duplicated logic has no outputs (only side effects) or a single output it simply can be extracted as a function. This corresponds to Extract Function refactoring.

Why not
Extracting a function reduces locality of the logic which might make the logic harder to follow (especially if the duplicated logic doesn't present a self-contained subproblem and there is no good semantic name for the extracted function)

Extracting a function makes readers of the code to navigate more.

See also the practice Prohibit overriding implementation of a function which has similar justification.

Extract a wrapper object
When the duplicated logic has multiple outputs or manifests in different places in the code, extracting a function might be ineffective in removing the repeated logic. In these cases, extracting a state-composing object or a decorator helps to consolidate the repeated logic.

Shift the interface boundary
Sometimes an API effectively requires a certain sequence of actions to be performed on the receiver object or the arguments before calling some function:

The normalization step can be pushed within the 's responsibility scope: The difference of this technique from extracting a function is that no new functions are added, but the existing functions are reorganized and their semantics are potentially changed.

Why not
Putting some boilerplate logic behind the interface boundary is a logical equivalent of denormalization in databases. If there are cases when the extra logic should not be performed before the main logic then additional functions should be added to the interface, increasing the API size. If the extra operations have side effects putting them behind the interface boundary complicates the semantics of the functions and creates an opportunity for mistakes if developers don't notice or forget about the side effects. To mitigate that, the side effects could be reflected in the names of the functions: for example, the changed function in the example above may be called.

It may be impossible to remove the extra semantics (the side effects) from the specification of the interface in the future, thus making it harder to change.

If the additional logic is idempotent then adding more variants of the function can be avoided at the expense of performing some unneeded work in some cases, thus reducing the runtime efficiency.

Parameterize the function or the class
When several functions share some logic, they can be merged into a single function with extra parameters controlling the difference in behavior.

Add a layer of abstraction
It's almost always possible to eliminate logic duplication by adding a new layer of abstraction: see the "fundamental theorem of software engineering".

Related

 * Don't make the client do anything the software could do
 * Extract repeated expression into a local variable
 * Code smell: object access chain
 * Code smell: function is used in many places
 * Split responsibilities between classes and functions