Object Oriented design is all about placing behavior and data together, of making the object responsible for its own operations. The problem then becomes identifying which object is responsible for what. This is usually pretty easy, since the natural owner of an operation is usually clear. Note that I don’t much care for the choice people make between things like parent.AddChild(child) vs. child.AddTo(parent). Both are equally good from my point of view. What I don’t want to see is this:
child.Parent = parent;
The reason for that is quite simple. This is a serious violation of the Tell, Don’t Ask protocol, and it means that someone is missing the pointing between the ownership of a particular operation and the instigator of that operation. The instigator is usually the UI, requesting that something will happen. Bad code will usually put a lot of the logic in the instigator side, rather than on the owner side.
Then we move into issues of cohesiveness and coupling, which guides us further in understanding how to place the appropriate responsibilities. All logic related to a particular aspect of the application should reside in the same location, so it is easy to work with, modify and change.
But by far the most common error I see people make is placing responsibilities on the instigator rather than on other parts of the system. There should be a very clear distinction between the two. Other than that, there is a lot of stuff that is just experience and understanding of the actual system.
In the end, all systems are refactorable, so you shouldn’t be afraid to make mistakes.