Object Oriented Analysis & Design Best Practices
Use UML
Use UML because it is the standard for OO notation. With deference to all the great work by other methodologists, engineers, and "thinkers", UML has won. The probability that someone understands what you are doing is significantly enhanced by having a (good-enough) core shared notation. Start with UML and then enhance it for needs it does not address.
Don’t draw models for everything
Don’t draw models for everything; instead, concentrate on the key areas. It is better to have a few diagrams that you use and keep up-to-date than to have many forgotten, obsolete models.
Prove Performance
Do not sacrifice a guideline for performance reasons until you see the profiling numbers. Only optimize when it will quantifiably be worth the maintenance penalty. Optimization is always harmful and rarely beneficial unless you have numbers to back it up. A better design (which these guideline try to encourage) will allow more precise and effective optimizations later when the numbers come in.
Two important principles to consider for high-quality software development are to:

Think from the client’s point of view
Think from the maintainer’s point of view
Understanding and considering these two customers’ needs during development makes most of the difference between poorly designed and very nicely designed systems. Object-oriented techniques can help support both of these customers’ needs, but the principles must always be on your mind. As the developer yourself, you will rarely forget your own needs.

The following maxims are from Kent Beck’s Smalltalk Best Practice Patterns [Beck 96]. These describe properties that should be in good OO designs and good OO code:

Once and only once In a program written with good style, everything is said once and only once.
Lots of little pieces Good code invariably has small methods and small objects.
Replaceable objects Good style leads to easily replaceable objects.
Movable objects …objects can be easily moved to new contexts.
Isolated rates of change …don’t put two rates of change together.

Elegance always pays off. In the short term it might seem like it takes much longer to come up with a truly graceful solution to a problem, but when it works the first time and easily adapts to new situations instead of requiring hours, days, or months of struggle, you’ll see the rewards (even if no one can measure them). Not only does it give you a program that’s easier to build and debug, but it’s also easier to understand and maintain, and that’s where the financial value lies. This point can take some experience to understand, because it can appear that you’re not being productive while you’re making a piece of code elegant. Resist the urge to hurry; it will only slow you down.
First make it work, then make it fast. This is true even if you are certain that a piece of code is really important and that it will be a principal bottleneck in your system. Don’t do it. Get the system going first with as simple a design as possible. Then if it isn’t going fast enough, profile it. You’ll almost always discover that “your” bottleneck isn’t the problem. Save your time for the really important stuff.
Remember the “divide and conquer” principle. If the problem you’re looking at is too confusing, try to imagine what the basic operation of the program would be, given the existence of a magic “piece” that handles the hard parts. That “piece” is an object—write the code that uses the object, then look at the object and encapsulate its hard parts into other objects, etc.
Your analysis and design must produce, at minimum, the classes in your system, their public interfaces, and their
relationships to other classes, especially base classes
. If your design methodology produces more than that, ask yourself if all the pieces produced by that methodology have value over the lifetime of the program. If they do not, maintaining them will cost you. Members of development teams tend not to maintain anything that does not contribute to their productivity; this is a fact of life that many design methods don’t account for.
Automate everything. Write the test code first (before you write the class), and keep it with the class. Automate the running of your tests through a makefile or similar tool. This way, any changes can be automatically verified by running the test code, and you’ll immediately discover errors. Because you know that you have the safety net of your test framework, you will be bolder about making sweeping changes when you discover the need. Remember that the greatest improvements in languages come from the built-in testing provided by type checking, exception handling, etc., but those features take you only so far. You must go the rest of the way in creating a robust system by filling in the tests that verify features that are specific to your class or program.
Write the t est code first (before you write the class) in order to verify that your class design is complete. If you
can’t write test code, you don’t know what your class looks like. In addition, the act of writing the test code will often flush out additional features or constraints that you need in the class—these features or constraints don’t always appear during analysis and design. Tests also provide example code showing how your class can be used.
All software design problems can be simplified by introducing an extra level of conceptual indirection. This fundamental rule of software engineering 1 is the basis of abstraction, the primary feature of object-oriented programming. An indirection should have a meaning This meaning can be something as simple as “putting commonly used code in a single method.” If you add levels of indirection (abstraction, encapsulation, etc.) that don’t have meaning, it can be as bad as not having adequate indirection.

Make classes as atomic as possible. Give each class a single, clear purpose. If your classes or your system design grows too complicated, break complex classes into simpler ones. The most obvious indicator of this is sheer size: if a class is big, chances are it’s doing too much and should be broken up.Clues to suggest redesign of a class are:

1) A complicated switch statement: consider using polymorphism.
2) A large number of methods that cover broadly different types of
operations: consider using several classes. 3) A large number of member variables that concern broadly different characteristics: consider using several classes.

Watch for long argument lists. Method calls then become difficult to write, read, and maintain. Instead, try to move the
method to a class where it is (more) appropriate, and/or pass objects in as arguments.
Don’t repeat yourself. If a piece of code is recurring in many methods in derived classes, put that code into a single method in the base class and call it from the derived-class methods. Not only do you save code space, you provide for easy propagation of changes. Sometimes the discovery of this common code will add valuable functionality to your interface.
Watch for switch statements or chained if-else clauses. This is typically an indicator of type-check coding, which means
you are choosing what code to execute based on some kind of type information (the exact type may not be obvious at first). You can usually replace this kind of code with inheritance and polymorphism; a polymorphic method call will perform the type checking for you, and allow for more reliable and easier extensibility.
From a design standpoint, look for and separate things that change from things that stay the same. That is, search
for the elements in a system that you might want to change without forcing a redesign, then encapsulate those elements in classes.
Don’t extend fundamental functionality by subclassing. If an interface element is essential to a class it should be in the base class, not added during derivation. If you’re adding methods by inheriting, perhaps you should rethink the design.
Less is more. Start with a minimal interface to a class, as small and simple as you need to solve the problem at hand, but don’t try to anticipate all the ways that your class might be used. As the class is used, you’ll discover ways you must expand the interface. However, once a class is in use you cannot shrink the interface without disturbing client code. If you need to add more methods, that’s fine; it won’t disturb code, other than forcing recompiles. But even if new methods replace the functionality of old ones, leave the existing interface alone (you can combine the functionality in the underlying implementation if you want). If you need to expand the interface of an existing method by adding more arguments, create an overloaded method with the new arguments; this way you won’t disturb any existing calls to the existing method.
Watch out for “giant object syndrome.” This is often an affliction of procedural programmers who are new to OOP and who end up writing a procedural program and sticking it inside one or two giant objects. With the exception of application frameworks, objects represent concepts in your application, not the application.
If you must do something ugly, at least localize the ugliness inside a class.
If you must do something nonportable, make an abstraction for that service and localize it within a class.
This extra level of indirection prevents the nonportability from being distributed throughout your program. (This idiom is embodied in the Bridge Pattern).
Choose composition first when creating new classes from existing classes. You should only used inheritance if it is
required by your design. If you use inheritance where composition will work, your designs will become needlessly omplicated.
Use design patterns to eliminate “naked functionality.” That is, if only one object of your class should be created, don’t bolt ahead to the application and write a comment “Make only one of these.” Wrap it in a singleton. If you have a lot of essy code in your main program that creates your objects, look for a creational pattern like a factory method in which you can encapsulate that creation. Eliminating “naked functionality” will not only make your code much easier to understand and maintain, it will also make it more bulletproof against the well-intentioned maintainers that come after you.
When you think you’ve got a good analysis, design, or implementation, do a walkthrough. Bring someone in from
outside your group—this doesn’t have to be a consultant, but can be someone from another group within your company. Reviewing your work with a fresh pair of eyes can reveal problems at a stage when it’s much easier to fix them, and more than pays for the time and money “lost” to the walkthrough process.
Hosted by www.Geocities.ws

1