The same setup (logging, validation, metric tick) or follow-up code appears around every call to a function — repeated boilerplate at every call site.
Setup or follow-up that happens around every call to a function moves inside the function, so the caller's contract shrinks.
Before the refactoring
log('start fetch');const data = fetch(url);log('start fetch');const data2 = fetch(url2);
After the refactoring
function fetchLogged(url) {log('start fetch');return fetch(url);}
Every caller must remember the boilerplate; missing it produces inconsistent behavior the function doesn't enforce; updates to the boilerplate touch every caller.
If the moved statements aren't always wanted, the function grows a flag argument — verify every caller really needs the moved behavior.
One fewer thing to remember at the call site; consistency is enforced by the function's definition, not by convention.
Moving statements into a function that some callers don't actually want — the function grows a flag argument to make the moved behavior conditional, which is a worse smell.