I'm relatively new to programming and keep getting overwhelmed when a problem can be solved in several different ways. For example, I was thinking about a program that accepts a time such as 12:13 and prints it in the terminal using ASCII art styled like a seven-segment display. I considered arrays, dictionaries, lookup tables, or hard-coded conditionals, but I'm not sure how to decide which approach is best. Do experienced developers follow a mental framework or checklist when tackling unfamiliar problems? How do you break the problem down, choose an implementation, and decide when efficiency or flexibility should influence the design?
5 Answers
The input-process-output model is a useful starting point. Identify what comes in, what should come out, and what transformations happen in between. Here that might be: read the time, validate and split it into digits, look up the segment pattern for each digit, assemble the rows, and print them. Thinking of each step as a small component makes the whole task much more manageable.
This general approach is often described as computational thinking: decompose the problem, recognize useful patterns, ignore irrelevant details through abstraction, and create an explicit sequence of steps. Practice is what makes it feel instinctive. Writing down the problem, building a simple proof of concept, and revisiting the design afterward will teach you more than trying to predict the ideal solution immediately.
There usually isn’t one perfect design waiting to be discovered before you start coding. Choose a reasonable approach, get a small version working, and then evaluate it. A lookup table is probably clearer than a large collection of conditionals for seven-segment digits, but experimenting with both can teach you why one is easier to maintain. Avoid optimizing before you know there is a real performance problem.
Start by decomposing the problem into smaller steps. For this example, you could define the seven segments, map each digit to the segments it uses, decide how one segment is drawn, parse the input time, and finally print the display one row at a time. Each piece can be implemented and tested independently before combining them.
You can work from both directions. Top-down, imagine the main function and give names to the smaller operations it needs, such as parseTime, digitPattern, and renderDisplay. Bottom-up, implement and test the simplest pieces first, such as drawing one digit or printing the digit 8. As the pieces become reliable, connect them into the larger solution.
Keeping those pieces relatively independent is important. It lets you replace the representation later without rewriting the input handling or output code.

A helpful way to think about the components is like building with blocks: each function does one small job, and the main program connects those functions together.