I wrote a binary calculator & binary teaching program in the Rust programming language. I was taking an iterative approach in that I decided to first get a basic "learn binary" game started. This game displays a hex or decimal number to the console and requires the player to enter the number in binary 1s and 0s as a means to help students learn binary.
I then decided to add binary calculator functionality to the program by creating a welcome screen and menu where the user selects between 1. Learn Binary 2. Binary Calculator and 3. Exit.
I then implemented the Binary Calculator functionality.
However, After I did this, I realized that within my Binary Calculator module, a "back to main menu" option was missing - so once a user entered the calculator, he/she would have to exit the program entirely to get to the Learn Binary game and vice versa.
However, in order to implement a "back to menu" feature, I'm realizing that I now have to abstract a loop out into the main function or one function lower, and now each function in succession needs to return some data so that this loop can know when to exit. I'm ending up having to change and add different return types to functions which is having a domino effect and has become more time consuming than expected.
This is just one small example, but I find myself facing this sort of thing often - is this typical in software engineering? Is it normal to have to go back and change a bunch of stuff when new features are added or is it a better idea to think all of this type of thing through ahead of time?
Note that my program is largely procedural but uses a couple OOP constructs as necessary.