Design is an iterative process. We may not perfectly specify every aspect of the program correctly on the first try, and that is okay. As we start implementing parts of our design, we may realize that a given task was much harder or easier than we thought. Or we may identify a better way entirely to solve the problem. In those situations, we will have to update our design to either change functions or design more functions to help do the work.
It may even be necessary to start implementing parts of our design before we have a complete understanding of the other aspects. Writing concrete code to solve part of a problem is sometimes the best way to test out if a particular idea works and to clarify our understanding of the problem.
Once we have designed one or more functions that are well-defined and simple enough to write, we can begin the implementation phase. This is where we translate our design into actual code.
Regardless of which strategy we used to design our program, implementation is much easier done bottom-up. We can start by implementing the lowest-level functions (those that do not depend on any other functions), then use those to build up to the higher-level ones. This allows us to test each piece as we go, making sure each function works correctly before we use it to build more complex code. It will be much easier to trust high-level functions if we know that the low-level functions they depend on work as expected.
It is possible to do top-down development. While implementing a high-level function, we can fake the existence of lower-level functions by creating stub versions of them. For example, if we were implementing a totalDays function that depends on a daysInMonth function, we could write a version of daysInMonth that always returns 30. It is clearly not correct, but we could use it to build the rest of the totalDays logic. However, it will be much harder to verify that the high-level function is correct if it depends on βstubbedβ lower-level functions that do not behave correctly in all cases.
But it can be difficult to accurately plan out every detail before you start working. As the saying goes, βno plan survives first contact with the enemyββassumptions we make during planning may turn out to be incorrect.