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 problem with large projects is that you can not oversee all the interactions between components. It is thus important to reduce the complexity of the project. Class and Sequence diagrams are too detailed for this phase of design. 

First try to think from a higher abstraction level. Think about major components and their responsibilities (their interface to other components), look at some architectural patterns for inspiration (no, not design patterns, these are too low level! MVC and Multi-Tier are architectural pattern examples).
For reasonably large projects, such a view should have about 3-5 components.

Only then you zoom into a certain component and try to design that. Now we are at the level of design patterns and class diagrams. Try to focus upon this part of the project, if you find you need to add a responsibility to one of the other components, just add it to your documentation/ todo list. Do not waste time thinking about the implications at this point they change far too quickly, review when the design is more solid. 

You do not need to fully design each component at this point, although it is probably wise to have a piece of code that implements the unimplemented components interface and generates simple but useful responses. This way, you can start development (and design) one component at a time and test it to a reasonable degree.

Of course, when new components are completed, you should test how (and if) they integrate with each other before moving on.

In very short: 
Take the OO and information hiding principle, and pull it up another level!

---

PS: 
Do a lot of sketching while designing, it's just like real architecture!

PPS: Try to approach the matter from different angles, think outside the box (although the box might be the way to go), discussing with peers can be very useful for this... and you have something to talk about over lunch.
I am afraid that this is not an answer *people like to hear*. Anyway, let me state my opinion. 

OOP should be viewed as one of the paradigms, not as the superior paradigm. OOP is good for solving certain kind of problems, like developing a GUI library. It also fits into the style of software development usually followed by large software companies - an elite team of *designers* or *architects* lays down the software design in UML diagrams or some other similar medium and a less enlightened team of *developers* translate that design into source code. OOP offer little benefit if you are working alone or with a small team of highly talented programmers. Then, it is better to use a language that supports multiple paradigms and will help you to come up with a prototype fast. Python, Ruby, Lisp/Scheme etc are good choices. The prototype is your design. Then you improve on that. Use the paradigm that is best to solve the problem at hand. If needed, optimize hot spots with extensions written in C or some other systems language. By using one of these languages, you also get *extensibility* for free, not just at the programmer level but also at the user level. Languages like Lisp can dynamically generate and execute code, which means your users can extend the application by writing small code snippets, in the language that the software itself is coded! Or if you choose to write the program in C or C++, consider embedding an interpreter for a small language like Lua. Expose functionalities as *plugins* written in that language.

I think that, most of the time OOP and OOD create software that are victims of over design. 

To summarize, my preferred way to write software is:

1. Use a dynamic language.
2. Write the design (prototype) in that language itself.
3. If necessary, optimize certain areas using C/C++.
4. Provide extensibility by way of the interpreter of the implementation language itself.

The last feature enables the software to easily adapt to specific user (including myself!) requirements.