Speaking in general terms, it is always best to model your problem in such a way that the true "hard constraints" are built-in. If your data model makes certain situations impossible, the solver will not have to waste time working around them when they happen. If you've already exhausted that well, then custom moves are your next best bet.
Let's take a hypothetical example where two vehicles must always move together. The generic moves are going to cause problems here. They may move one vehicle, which breaks a hard constraint for the other vehicle, and the only way to fix it is for the solver to randomly stumble upon another generic move that moves the other vehicle as well. The likelihood of that happening is not good, and solution quality will suffer for it.
The solution to this hypothetical is to replace the generic moves with custom moves - in this case, a custom move that always moves the two vehicles together, never breaking the hard constraint in the first place. But the best approach would be to design the model in such a way that the planning entity always has a pair of the vehicles as planning facts, and a planning variable is the destination - when the variable changes on the entity, both vehicles change automatically, without any need for custom moves.