When organizing a program, I often need to run several functions in sequence. One approach is to have a separate driver function call each step and pass the returned value to the next function:
```python
def run_pipeline():
x = input()
value1 = func1(x)
value2 = func2(value1)
value3 = func3(value2)
return value3
```
The other approach is to make each function call the next one internally, so `func1()` calls `func2()`, which calls `func3()`.
I usually prefer the first approach because each function remains independent and errors seem easier to trace. However, I'm not sure whether there is a generally preferred design, or whether the right choice depends on the situation. What factors should I consider?
5 Answers
There are other options for a configurable transformation pipeline, such as storing functions in a list and applying them in a loop. That can be useful when the steps vary at runtime, but for a short fixed sequence, explicit calls are generally clearer than introducing extra machinery.
The first approach is usually preferable when these are independent steps in a pipeline. The coordinating function makes the order visible, while each function does one focused task, returns a value, and stays reusable. You can test `func2()` by itself without automatically running `func1()` or `func3()`.
The second approach can still be appropriate when the later calls are implementation details of the first function. For example, a public `process_data()` function might call several private helper functions that only make sense in that specific process. In that case, callers only need to understand the high-level operation, not every internal step.
Think about abstraction and dependencies. If the sequence itself is important to understanding the program—such as reading input, transforming it, and producing output—put the sequence in an orchestrator and use meaningful function names. If `func2()` and `func3()` merely break up the internal work of `func1()`, nesting the calls can hide unnecessary detail from the caller.
The machine can execute either design, but future maintenance is the bigger concern. A clear call sequence helps readers and usually produces more manageable tracebacks. Keep functions focused, avoid making them automatically invoke unrelated later stages, and let the caller decide how to combine them.

That separation also makes it much easier to change the pipeline later—for example, replacing `func3()` or inserting another step without editing the earlier functions.