How do you design object oriented projects?

ArchitectureOopClass Design

Architecture Problem Overview


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?

Architecture Solutions


Solution 1 - Architecture

The steps that I use for initial design (getting to a class diagram), are:

  1. Requirements gathering. Talk to the client and factor out the use cases to define what functionality the software should have.

  2. Compose a narrative of the individual use cases.

  3. Go through the narrative and highlight nouns (person, place, thing), as candidate classes and verbs (actions), as methods / behaviors.

  4. Discard duplicate nouns and factor out common functionality.

  5. Create a class diagram. If you're a Java developer, NetBeans 6.7 from Sun has a UML module that allows for diagramming as well as round-trip engineering and it's FREE. Eclipse (an open source Java IDE), also has a modeling framework, but I have no experience with it. You may also want to try out ArgoUML, an open source tool.

  6. Apply OOD principles to organize your classes (factor out common functionality, build hierarchies, etc.)

Solution 2 - Architecture

Adding to what Scott Davies had to say:

  1. Make absolutely sure you know what your program is all about before you start. What is your program? What will it not do? What problem is it trying to solve?

  2. Your first set of use cases shouldn't be a laundry list of everything the program will eventually do. Start with the smallest set of use cases you can come up with that still captures the essence of what your program is for. For this web site, for example, the core use cases might be log in, ask a question, answer a question, and view questions and answers. Nothing about reputation, voting, or the community wiki, just the raw essence of what you're shooting for.

  3. As you come up with potential classes, don't think of them only in terms of what noun they represent, but what responsibilities they have. I've found this to be the biggest aid in figuring out how classes relate to each other during program execution. It's easy to come up with relationships like "a dog is an animal" or "a puppy has one mother." It's usually harder to figure out relationships describing run-time interactions between objects. You're program's algorithms are at least as important as your objects, and they're much easier to design if you've spelled out what each class's job is.

  4. Once you've got that minimal set of use cases and objects, start coding. Get something that actually runs as soon as possible, even though it doesn't do much and probably looks like crap. It's a starting point, and will force you to answer questions you might gloss over on paper.

  5. Now go back and pick more use cases, write up how they'll work, modify your class model, and write more code. Just like your first cut, take on as little at a time as you can while still adding something meaningful. Rinse and repeat.

Just my two cents. Hopefully it's useful.

Solution 3 - Architecture

When I had the chance, I normally use what I call the "three iterations rule".

In the first iteration (or startup), I devise the general layout of the application according to the model objects, the algorithms, and the expected (really expected, not maybe expected) future directions. I don't write design documents, but if I have to coordinate multiple people, a rough sketch of the procedure is of course needed, together with an analysis of dependencies and guesstimate of the time needed. Try to keep this phase to a minimum if, like me, you prefer a more agile method. There are cases where a strong design phase is needed, in particular when everything is known and true about the logic of your program, and if you plan to have a lot of interactions between features in your code. In this case, use cases or user stories provide are a good high level idea, in particular for GUI apps. For command line apps, and in particular libraries, try to write "program stories" in which you code against the library you have to develop and check how it looks. These programs will become functional tests of your library when completed.

After this first iteration, you will have a better understanding on how things interact, got out the details and the rough spots, solved issues with a slapped duct tape patch. You are ready to make use of this experience to improve, clean, polish, divide what was too large, coalesce what was too fragmented, define and use design patterns, analyze performance bottlenecks and nontrivial security issues. In general, all these changes will have a huge impact on the unit tests you wrote, but not on the functional tests.

When you complete this second iteration, you will have a little jewel, well tested, well documented, and well designed. Now you have both the experience and the code to do the third iteration, extend. You will add new features and use cases to improve your application. You will find rough spots and you will eventually enter a fourth iteration which is analogous to the second one. Rinse and repeat.

This is my general approach to software design. It is similar to spiral design, with short, three months iterations, and elements of Agile development, that allows you to learn the issues and get to know your software and its field of application. Of course, it's a matter of scalability, so if the application is so large to involve hundreds of developers, things are a bit more complex than this, but in the end I guess the idea is always the same, divide et impera.

So summing up:

  1. In iteration one, you get a taste of it, and learn
  2. In iteration two, you clean up your product and prepare it for the future
  3. In iteration three, you add new features and learn more
  4. goto 2

Solution 4 - Architecture

The most interesting source I know of regarding this is Part D of Object Oriented Software Construction, 2nd Edition by Bertrand Meyer.

Part D: Object-oriented methodology: applying the method well

19: On methodology, 20: Design pattern: multi-panel interactive systems, 21: Inheritance case study: "undo" in an interactive system, 22: How to find the classes, 23: Principles of class design, 24: Using inheritance well, 25: Useful techniques, 26: A sense of style, 27: Object-oriented analysis, 28: The software construction process, 29: Teaching the method

Interestingly, the chapter 22. How to find the classes is available online.

Solution 5 - Architecture

It's oft repeated but completely true - understand your data.

For OOP your classes should describe salient pieces of information and how they interact.

If you have a mental model that well-describes the behaviour and lifetime of the data, you'll have an easy ride laying out your classes.

This is simply an extension of: Know exactly what you're trying to do.

Solution 6 - Architecture

Try using behavior driven development. It'll be hard to break your old habits, but I've found that BDD really is your best bet when it comes to developing in the real world.

http://behaviour-driven.org/

Solution 7 - Architecture

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.

Solution 8 - Architecture

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).

Solution 9 - Architecture

Design Patterns

Creational Design Patterns

Singleton - Ensure that only one instance of a class is created and Provide a global access point to the object.

Factory(Simplified version of Factory Method)- Creates objects without exposing the instantiation logic to the client and Refers to the newly created object through a common interface.

Factory Method - Defines an interface for creating objects, but let subclasses to decide which class to instantiate and Refers to the newly created object through a common interface.

Abstract Factory - Offers the interface for creating a family of related objects, without explicitly specifying their classes.

Builder - Defines an instance for creating an object but letting subclasses decide which class to instantiate and Allows a finer control over the construction process.

Prototype - Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.

Behavioral Design Patterns

Chain of Responsibiliy - It avoids attaching the sender of a request to its receiver, giving this way other objects the possibility of handling the request too.

  • The objects become parts of a chain and the request is sent from one object to another across the chain until one of the objects will handle it.

Command - Encapsulate a request in an object, Allows the parameterization of clients with different requests and Allows saving the requests in a queue.

Interpreter - Given a language, define a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language / Map a domain to a language, the language to a grammar, and the grammar to a hierarchical object-oriented design

Iterator - Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.

Mediator - Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Observer - Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Strategy - Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Template Method - Define the skeleton of an algorithm in an operation, deferring some steps to subclasses / Template Method lets subclasses redefine certain steps of an algorithm without letting them to change the algorithm's structure.

Visitor - Represents an operation to be performed on the elements of an object structure / Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Null Object - Provide an object as a surrogate for the lack of an object of a given type. / The Null Object Pattern provides intelligent do nothing behavior, hiding the details from its collaborators.

Structural Design Patterns

Adapter - Convert the interface of a class into another interface clients expect. / Adapter lets classes work together, that could not otherwise because of incompatible interfaces.

Bridge - Compose objects into tree structures to represent part-whole hierarchies. / Composite lets clients treat individual objects and compositions of objects uniformly.

Composite - Compose objects into tree structures to represent part-whole hierarchies. / Composite lets clients treat individual objects and compositions of objects uniformly.

Decorator - add additional responsibilities dynamically to an object.

Flyweight - use sharing to support a large number of objects that have part of their internal state in common where the other part of state can vary.

Memento - capture the internal state of an object without violating encapsulation and thus providing a mean for restoring the object into initial state when needed.

Proxy - provide a “Placeholder” for an object to control references to it.

Solution 10 - Architecture

I would recommend to you to use BlueJ and also ActiveWriter to learn and also to develop a good understanding on objects. The book recommended is also a nice resource.

From Wikipedia:

alt text

> BlueJ is an Integrated Development > Environment for the Java programming > language, developed mainly for > educational purposes, but also > suitable for small-scale software > development.

Additionally it uses UML and for me it was a good resource to comprehend several things about modeling objects.

alt text

ActiveWriter is a tool to model entities and relations, it also generates code and is easy to make changes. It will save you time and for agile development is very suitable.

alt text
(source: altinoren.com)

Solution 11 - Architecture

You asked question that lots of authors use to write a book. There is number of methodologies and you should pick one that seems "prettiest" to you.
I can recommend book "Domain Driven Design" by Eric Evans. Also, check site dddcommunity.org.

Solution 12 - Architecture

First of all - design should come from your soul. You must feel it by your every fibre. I usually walk it down for two or three months before I start doing anything, Just walking down the streets (really). And thinking. Walking is a good meditation, you know. So it lets you to concentrate well.

Secondly - use OOP and classes only where a natural object hierarchy exists. Don't 'screw-in' it to that artificially. If no strict hierarchy exists (like in most business applications) - go for procedural/functional, or, at least use objects only as data containers with isolated accessors.

And the last - try to read this: The Algorithm of Creative Thinking

Solution 13 - Architecture

Just quoting http://www.fysh.org/~katie/computing/methodologies.txt

And at the core of RUP is a small area where you have to use OO design talents.... if you don't have them, it's like having a methodology for running the 100m.

"Step 1: write about running really fast. Step 2: Go and draw a plan of the racetrack. Step 3: go and buy really tight lycra shorts. Step 4: run really, really, really fast. Step 5: cross line first"

It's that step 4 that's the tough one. But if you put lots of emphasis on 1,2,3 and 5 it's possible no-one will notice and then you could probably make a lot of money selling the methodology to would be athletes who think there's some "secret" to being a 100m runner over

Solution 14 - Architecture

I think the answer here should be very different depending on the real world experience of the guy asking.

If you have just one or two years work experience then you must go to the point that is: how do you get to the point you really know your data and understand exactly what you're trying to do?

Yeah, if you have been working in the real world 5+ years then you would choose between any of the many software development processes models or techniques.

But you don't get experience by reading books only. You should learn by working in a good group under a good leadership.

If that's not possible then you should just do by yourself. Begin iterating by coding a probably very nasty piece of code, learning your errors, dumping it all, coding a better one and so on.

You'll learn a lot about your codebase. The tools are tools, they will teach you nothing.

Solution 15 - Architecture

  1. study & master Design Patterns.
  2. Next, learn about the Domain Driven Design
  3. After that, learn the requirement gathering

> 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.

  1. You know about the step 3. You need to master it. I mean, via a lot of practice to make it become your second nature. That's because the method you learn, is simply against the way we used to have. So you need to really master it. Otherwise, you will always find yourself go back to your original way of doing thing. This is somehow like Test Driven Process, where a lot of java developer give it up after a few tries. Unless they fully master it, otherwise it's just a burden to them

  2. Write use cases, especially for alternate course. Alternate course occupy more than 50% of our development time. Normally when your PM assign you a task, for instance, create a login system, he will think it's straight forward, you can take 1 day to finish it off. But he never take into account that you need to consider, 1. what if user key in wrong password, 2. what if user key in wrong password for 3 times, 3. what if user doesn't type in user name and etc. You need to list them out, and show it to your PM, ask him to reschedule the deadline.

Solution 16 - Architecture

If you have domain expertise on the project you are going to work on like say banking. It's easy to structure your objects and you know how those enhancements come every other day.

If you don't have that expertise work with someone who has that expertise and convert those ideas into technical details.

If you are confused about how to structure your project design. BLINDLY follow "pragmatic programmer" book. I was in same situation before, try reading a chapter from that book. you will see the difference, It will change the way you think as a software developer.

Solution 17 - Architecture

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.

Solution 18 - Architecture

Learn design patterns. It has been my personal revolution the past two years regarding OOP. Get a book. I would recommend you this one:

Head First Design Patterns

It is in Java but it can be extensible to any language.

Solution 19 - Architecture

I use Test-Driven Design (TDD). Writing the test first actually helps lead you to a design that is clean and correct. See http://en.wikipedia.org/wiki/Test-driven_development.

Solution 20 - Architecture

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.

Solution 21 - Architecture

Solution 22 - Architecture

One useful technique is to relate your unique problem description to something you can find in the real world. For example, you are modelling a complex health care system that will take the world by storm. Are there any examples you can readily call upon to model this?

Indeed. Observe how the side pharmacy would operate, or the doctor's room.

Bring your domain problem down to something understandable to you; something to which you can relate.

Then once the "players" within the domain start to appear obvious, and you start to model your code, opt for a "provider-consumer" modelling approach i.e. your code is the "provider" of the model, and you are the "consumer".

Relating to the domain and understanding it at a high level is key part of any design.

Solution 23 - Architecture

During my adventures of designing class structures, I’ve noticed that it’s very helpful to start with writing some pseudo-code. That means: I start with “writing” some general fragments of application’s code on a highest level, play with it, and discover the elements that are appearing – in fact, the elements that I – as a programmer – would like to use. It’s a very good starting point for designing general structure of modules and their interactions. After few iterations the whole structure starts to look more like a full system of classes. It’s a very flexible way to design parts of code. You can call it a programmer-oriented design.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVictorView Question on Stackoverflow
Solution 1 - ArchitectureScott DaviesView Answer on Stackoverflow
Solution 2 - ArchitectureDarrylView Answer on Stackoverflow
Solution 3 - ArchitectureStefano BoriniView Answer on Stackoverflow
Solution 4 - ArchitectureDaniel DaranasView Answer on Stackoverflow
Solution 5 - ArchitectureDave GambleView Answer on Stackoverflow
Solution 6 - ArchitectureEric the RedView Answer on Stackoverflow
Solution 7 - ArchitectureNomeNView Answer on Stackoverflow
Solution 8 - ArchitectureSteve GilhamView Answer on Stackoverflow
Solution 9 - ArchitectureSauronView Answer on Stackoverflow
Solution 10 - ArchitectureNelson MirandaView Answer on Stackoverflow
Solution 11 - ArchitecturezendarView Answer on Stackoverflow
Solution 12 - ArchitectureThevsView Answer on Stackoverflow
Solution 13 - ArchitecturemartinView Answer on Stackoverflow
Solution 14 - ArchitectureIlDanView Answer on Stackoverflow
Solution 15 - ArchitecturejanetsmithView Answer on Stackoverflow
Solution 16 - ArchitectureBroken LinkView Answer on Stackoverflow
Solution 17 - ArchitectureVijay MathewView Answer on Stackoverflow
Solution 18 - ArchitectureDavid EspartView Answer on Stackoverflow
Solution 19 - ArchitectureDavid AllenView Answer on Stackoverflow
Solution 20 - Architectureuser133018View Answer on Stackoverflow
Solution 21 - ArchitectureChrisWView Answer on Stackoverflow
Solution 22 - ArchitectureMike JView Answer on Stackoverflow
Solution 23 - ArchitectureDariusView Answer on Stackoverflow