Symmetry in code is valuable, and often subtle. When I find symmetry in code, I feel it's a positive sign that the design is working well.
I like temporal symmetry. When something opens at the very beginning of a request, I'll expect it to close at the very end of a request.
I like conceptual symmetry. Milan Negovan has a discussion about symmetry on an old blog post (Achieving Code Symmetry), and includes examples from Kent Beck's Implementation Patterns book.
I also like structural symmetry. It sounds silly to judge code based on it's visual representation in a text editor, but I was recently thrown by a bit of code that looked like this.
if (widget.IsRegular) { service.Process(widget); } else { var result = widget.Calculation(); widget.ApplyResult(result); service.ProcessSpecial(widget); }
When you get down to look at the detail of the code you might find it violates any number of principles and object oriented design goals, but with just a glance something appears amiss. One path appears more complex than the other. Why? The asymmetry breaks my concentration and makes the code harder to read.
After a bit of refactoring, the code could look like this:
if (widget.IsRegular) { service.Process(widget); } else { service.ProcessSpecial(widget); }
Now there is a balance in the code, and any additional problems might be easier to see.
Comments
The second example hides that complexity and moves the widget-related code even further away from the widget class. For example, here is what it might end up looking like:
// ... Original Code ...
widget.ProcessWith(service);
class Widget {
public void ProcessWith(IService service){
// Was it necessary to expose the IsRegular flag? Isn't that internal state?
if(IsRegular) {
service.Process(this);
} else {
// This next line looks weird now. (And it should, it's likely a design smell)
// Why do we expose a calculation publicly just to update our internal state?
ApplyResult(Calculation());
service.ProcessSpecial(this);
}
}
}
Again, this may just be caused by the fact that this is a generic example and the original point is still valid, I'd just be wary that by moving complexity this way you might be sweeping it under a rug instead of improving it.
widget.ApplyResult(widget.Calculation());
??
It's like you're missing some explanation here.