I have a complex system to design. I have two ways:
Top-down: I will design many interfaces and contracts. Afterwords, I will implement these interfaces, and write a prototype to verify the design.
Bottom-up: I will write code to make the system run. Afterwords, I will extract interfaces and contracts from solid code. The distilled interfaces and contracts is my design. It's rule "make it run, make it right".
What is better way? From my opinion, I will choose Bottom-up. Because Top-down is very difficult, no one can design many interfaces at high abstract level,at least it's hard for me. When I write solid implementation to verify the initial design, there are many unreasonable things which force me to re-design from scratch. While I use Bottom-up, I feel quite "safe", it can run at least.
As others have said, it's usually a mix. On a more practical level, the following approach usually helps:
Start by going ABSTRACT Top-Down. Namely, break the system/design into logical components to solve tasks. But don't design precise finalized interfaces for those components. Proceed recursively till some components you arrive at are of "implementation-possible" size (e.g. are the size of a single function/method/class)
Then, go through the resultant component list Bottom-Up, and start designing first draft of interfaces/contracts.
Then, go through the resultant component list Bottom-Up, and start implementing them. This will allow you to:
Have a working and testable code immediately (no need to wait for underlying components to be implemented to test)
You can synthesize the final version of interfaces/contracts for higher level components based on the needs of the already-completed lower level components.