Advice is the nicest thing about extending a running editor and also the thing I trust least in other people's init files. (Mine included.)
advice-add with :around wraps a function without touching its definition, and advice-remove takes the wrapper off again. You can do all of it from *scratch* while the editor keeps running, which is the whole charm. The catch is that advice applies to every caller, including packages that never asked for it. describe-function does list active advice in the help buffer, so C-h f on the misbehaving function is the first thing to try when something acts strange.
The other tool people forget is dynamic scope. A variable defined with defvar is special, so a let around a call rebinds it for everything that call reaches, all the way down, and the old value comes back when the let exits. With lexical-binding on, ordinary locals are lexical but those special variables stay dynamic. Binding case-fold-search around the one call you care about is often cleaner than advising anything.
My rough order. A hook if the package offers one, a dynamic let if a variable controls the behavior, advice last.