When developing functionality in an app there are many design challenges for the developer. One of the most important ones that determines how easy / hard the entire solution architecture is to develop and maintain over time is how well each function / module / class that is created hides the complexity within.
The main purpose of a module in a larger system is to hide complexity
An example to illustrate this is when developing interactive CAD-configurators where the user can place components with the mouse, but a strict set of rules still need to be applied. Lets say the user can create a door on a wall section with the click of a mouse button. This requires both infomation about the click, the door and how this comes together in relation to existing components (like a wall).

The following four alternatives for the addDoor function illustrates how different approachers will impact how much complexity is hidden
1 – No complexity hidden
assembly.addDoor(doorObject, position)
An entire door object needs to be created outside the function and rules affecting position also needs to be handled outside the function – no complexity hidden
2 – Door complexity hidden
assembly.addDoor(doorType, size, position)
Only type and size is needed here but position rules still need to be outside the function – door complexity hidden
3 – Positioning complexity hidden
assembly.addDoor(doorComponent, requestedPosition)
The door object is created outside but the position is just a request and rules for actual position is computed inside – position rule complexity hidden
4 – Both door and position complexity hidden
assembly.addDoor(doorType, size, requestedPosition)
Combining 2 and 3 results in hiding of both door and placement rule complexities
There will always be trade-offs that keep you from hiding all complexity in the function. But becoming aware of this mechanism is the first step to designing good modules and well functioning architecture.