I have a block of code that branches into 2 pathways, let's call them the "simple" and "complex" branch, based on user input.
Either the simple or complex logic has 4 steps, let's call them A, B, C and D. A, B and C each have 2 different variations depending on whether we're in the simple or complex branch.
In the complex case, A, B and C are long enough where it makes sense for them to be broken up into their own methods. In the simple case, these reduce to nearly 2-3 liners.
Because the simple and complex case correspond to different user inputs, I feel it's easier and less mentally taxing to think about the problem with 1 if statement branching into 2 different methods, rather than 1 method with multiple if statements inside. This way, when I look at the methods of either branch, I'm only having to ever think about the logic of 1 case at the time rather than look in and out of if statements to see the program flow.
Now the dilemma is that both methods share identical code for D logic, and while they correspond to different user inputs, D is unlikely to ever vary between them. In the complex method, A, B and C are broken out into separate subfunctions, so it is logcally consistent for D, which is the same logical level as A B and C, to also be broken out into a separate function. In-lining, in this case, hurts readability.
However, in the simple case, A, B and C are all in-lined into the simple() method. Each of these steps is short enough that any separation into subfunctions would hurt readability (and, since D represents a similar level of step in the process, it would be logically inconsistent to break D into a sub method).
I'm currently most inclined to have D in-lined in the simple case, so that A, B, C and D can be read in one function in simple(), and then have identical logic for D broken out into a sub-function in the complex case. This violates DRY, but I feel this improves readability.
In summary, in pseudocode:
if(condition)
simple()
else
complex()
function simple() //All in-lined in simple()
Asimple;
Bsimple;
Csimple;
D;
function complex()
Acomplex();
Bcomplex();
Ccomplex();
D();
D is copy-pasted in D() and in-lined in simple(), but I believe this is more readable as both simple and complex have their internal logic at a consistent level of decomposition. And, by keeping logic all together in the simple case and decomposed on the complex case, this maximizess readability by keeping functions neither too short nor too long. Does this seem like an appropriate time to violate DRY?