Skip to main content

Section 12.8 Bottom-Up Design

The other major strategy for program design is bottom-up. This method involves starting with the lowest-level functions, which handle simple, specific tasks, and then combining them to form higher-level functions. We of course still need some understanding of the problem we are trying to solve, but we do not start out by trying to solve that entire problem at once.
This can be a useful approach when we do not perfectly understand a problem, or we don’t see a clear path to a solution. In these cases, it can be easier to identify simple, concrete tasks that will need to happen than to reason about larger, more abstract parts of the problem. The hope is that as we design (or even build) the functions for low-level tasks, we will identify ideas for higher-level functions that combine those basic tasks.
The downside of bottom-up design is that it is less goal directed: instead of starting from the exact high-level behavior we want, we are trying to piece together the solution from the ground up. While doing that, we are more likely to design functions that do not fit well together or end up being totally unnecessary.

Example 12.8.1. A Bottom-Up Design.

A bottom-up design for our date program would start by trying to identify small bits of work that we think will need to get done. Maybe we don’t initially think of turning each date into a number of days since 0/0/0. But we do realize that we will need to break a string like "3/4/2023" into its component parts. So we might start with:
  • int getMonth(string date) Get the month as an integer.
    • Precondition: a string like "3/4/2023".
    • Postcondition: an integer representing the month.
  • int getDay(string date) Get the day as an integer.
    • Precondition: a string like "3/4/2023".
    • Postcondition: an integer representing the day.
  • int getYear(string date) Get the year as an integer.
    • Precondition: a string like "3/4/2023".
    • Postcondition: an integer representing the year.
At this point, we could stop and build all three of these functions and test them out. Doing this will help us test out our understanding of the problem.

Note 12.8.2.

We arrived at a point where we could start writing code much sooner by focusing on concrete details initially instead of the big picture.
Once we have those functions, we maybe get a sense of what we could do with them. It feels like we might need to know how many days are in a given month. So we might add a function to handle that:
So maybe we build that function.
Then, maybe we realize it would be good to combine the month/day into a single total number of days. So 1/3 would be 3 days, 2/5 would be 36 days (31 for January plus 5 in February), etc... That might lead us to adding a totalDays function that takes the month and day.
  • int totalDays(int month, int day) Get the total number of days represented by a given month/day combo.
    • Precondition: an integer month and day.
    • Postcondition: the number of days up to and including that day of the year.
As we start to implement that function, we might realize that our daysInMonth is not as helpful as we thought. Instead, what we really need is a function that tells us how many days have passed before a given month. It is less valuable to know that there are 31 days in March than it is to know there are 59 days before March starts. So we might need to go write a new function int daysBeforeMonth(int month). (It would look like the version we designed in the top-down approach).

Note 12.8.3.

We may not even need the daysInMonth function at all if we have daysBeforeMonth. This is the danger of starting with low-level details - it is easier to build things that seem like they make sense only to later realize that they don’t actually help solve your high-level problem.
Once we have those functions, the next step might be to decide to write a function to compute the total number of days for the month/day and year. And eventually we would need to get the user input.

Insight 12.8.4.

The pros and cons of bottom-up design both stem from starting from the details. We need less big-picture understanding to make progress, but because of that we are more likely to build functions that do not end up being useful in the final program.

Checkpoint 12.8.1.

You have attempted of activities on this page.