Question: I'm working on a large project (for me) which will have many classes and will need to be extensible, but I'm not sure how to plan out my program and how the classes need to interact.

I took an OOD course a few semesters back and learned a lot from it; like writing UML, and translating requirements documents into objects and classes. We learned sequence diagrams too but somehow I missed the lecture or something, they didn't really stick with me.

With previous projects I've tried using methods I learned from the course but usually end up with code that as soon as I can say "yeah that looks something like what I had in mind" i have no desire to dig through the muck to add new features.

I've got a copy of Steve McConnell's *Code Complete* which I continually hear is amazing, here and elsewhere. I read the chapter on design and didn't seem to come out with the information I'm looking for. I know he says that it's not a cut and dried process, that it's mostly based on heuristics, but I can't seem to take all his information and apply it to my projects.

So **what are things you do during the high level design phase (before you begin programming) to determine what are the classes you need (especially ones not based on any 'real world objects') and how will they interact with each other**?

Specifically I'm interested in what are the methods you use? What is the process you follow that usually yeilds a good, clean design that will closely represent the final product?

Answer: 
The technique I've used in real projects with reasonable success is Responsibility Driven Design, inspired by Wirfs-Brock's book. 

Start with the top level user stories, and with colleagues, at a whiteboard, sketch the high-level interactions they imply. This gets you the first idea of what the big modules are; and an iteration or two of high level CRC-card like play you should have stabilised a list of major components, what they do and how they interact.

Then, if any of the responsibilities are large or complex, refine those modules down until you have things that are small and simple enough to be objects, by playing out the interactions inside the module for each of the major operations identified by the higher level interactions. 

Knowing when to stop is a matter of judgement (which only comes with experience).
Honestly, a good step would be going back and looking at flow charting and sequence diagramming. There are a ton of good sites that show you how to do it. I find it to be invaluable when looking at how I want to break down a program into classes as I know exactly what the program needs inputted, computed, and outputted and each step can be broken down into one part of the program.