Move Statements into Function
Intent
Section titled “Intent”When a line of code is always paired with a call to some function — running just before it or just after it, at every single call site — that line belongs inside the function. Move it in. The function now owns the complete job, and callers shrink to a single call they cannot get wrong.
The smell
Section titled “The smell”You find the same preparatory or trailing statement copy-pasted above or below a function call everywhere it appears. Maybe every caller of renderName first writes an opening tag, or every caller of fetchOrder logs the same line afterwards. That repeated statement is part of the behaviour the callers expect, yet it lives outside the function, where each new caller has to remember to add it. Forget once and you have a quiet bug. The duplication is a sign the statement wants to move in.
Before → After
Section titled “Before → After”A function that emits a person’s photo HTML. Every caller writes the same <p> heading line right before calling it. That heading is really part of “render the photo block”, so we move it in.
// Beforefunction photoData(photo: Photo): string { return [ `<p>location: ${photo.location}</p>`, `<p>date: ${photo.date.toDateString()}</p>`, ].join('\n');}
function renderPerson(person: Person, photo: Photo): string { return [ `<p>${person.name}</p>`, `<p>title: ${photo.title}</p>`, // repeated at every call site photoData(photo), ].join('\n');}
function emitPhoto(photo: Photo): string { return [ `<p>title: ${photo.title}</p>`, // repeated here too photoData(photo), ].join('\n');}
// Afterfunction photoData(photo: Photo): string { return [ `<p>title: ${photo.title}</p>`, // moved in — now owned by photoData `<p>location: ${photo.location}</p>`, `<p>date: ${photo.date.toDateString()}</p>`, ].join('\n');}
function renderPerson(person: Person, photo: Photo): string { return [`<p>${person.name}</p>`, photoData(photo)].join('\n');}
function emitPhoto(photo: Photo): string { return photoData(photo);}# Beforedef photo_data(photo): return "\n".join([ f"<p>location: {photo.location}</p>", f"<p>date: {photo.date:%Y-%m-%d}</p>", ])
def render_person(person, photo): return "\n".join([ f"<p>{person.name}</p>", f"<p>title: {photo.title}</p>", # repeated at every call site photo_data(photo), ])
def emit_photo(photo): return "\n".join([ f"<p>title: {photo.title}</p>", # repeated here too photo_data(photo), ])
# Afterdef photo_data(photo): return "\n".join([ f"<p>title: {photo.title}</p>", # moved in — now owned by photo_data f"<p>location: {photo.location}</p>", f"<p>date: {photo.date:%Y-%m-%d}</p>", ])
def render_person(person, photo): return "\n".join([f"<p>{person.name}</p>", photo_data(photo)])
def emit_photo(photo): return photo_data(photo)// Beforefunc photoData(p Photo) string { return fmt.Sprintf("<p>location: %s</p>\n<p>date: %s</p>", p.Location, p.Date.Format("2006-01-02"))}
func renderPerson(person Person, p Photo) string { return fmt.Sprintf("<p>%s</p>\n<p>title: %s</p>\n%s", person.Name, p.Title, photoData(p)) // title repeated everywhere}
func emitPhoto(p Photo) string { return fmt.Sprintf("<p>title: %s</p>\n%s", p.Title, photoData(p))}
// Afterfunc photoData(p Photo) string { return fmt.Sprintf("<p>title: %s</p>\n<p>location: %s</p>\n<p>date: %s</p>", p.Title, p.Location, p.Date.Format("2006-01-02")) // moved in}
func renderPerson(person Person, p Photo) string { return fmt.Sprintf("<p>%s</p>\n%s", person.Name, photoData(p))}
func emitPhoto(p Photo) string { return photoData(p)}// Beforefn photo_data(p: &Photo) -> String { format!("<p>location: {}</p>\n<p>date: {}</p>", p.location, p.date)}
fn render_person(person: &Person, p: &Photo) -> String { // title line repeated at every call site format!("<p>{}</p>\n<p>title: {}</p>\n{}", person.name, p.title, photo_data(p))}
fn emit_photo(p: &Photo) -> String { format!("<p>title: {}</p>\n{}", p.title, photo_data(p))}
// Afterfn photo_data(p: &Photo) -> String { // moved in — now owned by photo_data format!("<p>title: {}</p>\n<p>location: {}</p>\n<p>date: {}</p>", p.title, p.location, p.date)}
fn render_person(person: &Person, p: &Photo) -> String { format!("<p>{}</p>\n{}", person.name, photo_data(p))}
fn emit_photo(p: &Photo) -> String { photo_data(p)}Mechanics
Section titled “Mechanics”- Confirm the candidate statement runs adjacent to the call at every site. If even one caller does it differently, this move is wrong — that variation is real.
- If the call site holds other code, first apply Extract Function to isolate exactly the call plus the repeated statement into one helper. Now you only have one place to work.
- Move the repeated statement into the target function — at the top if it ran before the call, at the bottom if it ran after.
- Run your tests.
- Delete the now-redundant statement from each caller, one at a time, running tests after each deletion.
- If you created a temporary helper in step 2, inline it once every caller is clean.
When to use / trade-offs
Section titled “When to use / trade-offs”Use this when a statement is genuinely part of the function’s responsibility but happens to live outside it. Folding it in removes duplication and makes the function a complete, hard-to-misuse unit.
Do not use it when callers differ in whether or how they run the statement — forcing a shared step onto a function that some callers want to skip just trades duplication for a flag parameter, which is worse. The inverse refactoring is Move Statements to Callers: when a function bundles a step that only some callers want, push it back out.