CSC223 2004F, Class 23: Design Heuristics (1): Basics Admin: * This week: * Monday: Chapters 1-3 (Basics) * Wednesday: Chapters 4-7 (Relationships) * Friday: Chapters 8-10 (The Rest) * How much reading did you get done? * About as much as SamR. * Take-home exam distributed Wednesday, due a week from Friday. * In-class exam next Monday. * It wouldn't be Monday without a quiz! * Title your email "Week 8 Quiz" * 1. What is your favorite heuristic from chapters 1-3? Why? * 2. What is your least-favorite heuristic from chapter 1-3? Why? Overview: * Why have/study design heuristics? * Discussion of Quiz Answers * Questions on the reading? * Basic philosophy: Encapsulation! * Problems with this philosophy /Why Study Heuristics (or at least this book)/ * Mr. Walker recommended it. * We cram so much into 152/153, some key ideas of object-oriented design get lost: This book provides a nice discussion of what it means to do OOD. It can reinforce or provide the basics. * Few of you are good object-oriented programmers. Heuristics help get you there. * The book is designed well for learning. * Basic idea: You can improve your skills at OOD by keeping in mind (and checking) some principles as you look at your design. (60!) /Context: Encapsulation/ * Encapsulation: Two things * Groups data and related operations together * "Protects" data: Interact primarily through methods/messages * Why encapsulate? * Easier to change code without seeing problems propagate. * Encapsulated code is easier to reuse. /Discussion of Quiz Answers/ Faves: * 2.2: Users of a class must be dependent on its public interface, but a class should not be dependent on its users. * Straightforward. * Reminder that we do OOP in part because of genericism. * 2.3: Minimize the number of messages in the protocol of a class. ("message" = "methods"; "protocol" = "provided by class") * His reason: If you have too much, you can't find what you want. * My reason: If you have too much, you don't focus on the best implementation of the most important operations. * Another reason: Bloating may suggest that refactoring is needed. * 3.3: Beware of classes that have many accessor methods defined in their public interface, many of them imply that related data and behavior are not being kept in one place. * When you violate this, you focus on objects as repositories for data, and not as combinations of data and the methods that operate on them. Least fave: 2.7: Classes should only exhibit nil or export coupling with other classes. * Doesn't like it because it's unclear. * What if you really want a struct and not an object? Example: What if you're building linked lists and want a "Node" for the implementation? * Java's packages provide a reasonable compromise. * 2.8: A class should capture one and only one key abstraction. * Doesn't like because it's unclear. * Is this an instance of "don't make God classes?" * When you ask: What is the purpose of this class? you shouldn't have multiple answers. * Example: Don't design generic "collections" that can support *all* the reasonable collection oprations * Like sets, they provide membership checking * Like lists, they provide iteration * Like linear structures, they provide "next" * Java's vectors meet this idea in one way: They provide "values indexed by number" * They fail to meet it in another, since they act as queues, lists, and much more in addition to "values indexed by number" * Why this design? * Avoid deep inheritance hierachies? * Because we can? * Because it matches the wonderful Perl model. * 3.9: Do not turn an operation into a class. * java.util.Comparator is an excellent instance of the benefits of turning an operation into a class. /Detour: Dangers of Multi-purpose classes/ * What is the efficiency of "push/pop" in java.util.Vector? * What is the efficiency of "enqueue/dequeue" in java.util.Vector? * It is likely that one is O(1) and one is O(n) and you don't know which. /Detour: Coupling/ * Nil coupling: Class X and class Y never interact. * Export coupling: Class X only uses the public methods of class Y. * Overt coupling: Class X explicitly relies on the implementation of class Y. (Possibly by using inappropriately public fields.) * Kills encapsulation. * However, we expect that people who change Y know to be careful about the stuff that others could have overtly coupled to. * Covert coupling: Class X uses trickery to rely on the implementatino of class Y. * In Java, you can make a new class that's part of an existing package, even if you don't own that package. * Really kills encapsulation. * Surreptitious coupling: * Read about it for Wednesday. /Questions on the Reading/ /The Heuristics/ 2.1: All data should be hidden within its class. 2.2: Users of a class must be dependent on its public interface, but a class should not be dependent on its users. 2.3: Minimize the number of messages in the protocol of a class. 2.4: Implement a minimal public interface which all classes understand (e.g. operations such as copy (deep versus shallow), equality testing, pretty printing, parsing from a ASCII description, etc.). 2.5: Do not put implementation details such as common-code private functions into the public interface of a class. 2.6: Do not clutter the public interface of a class with things that users of that class are not able to use or are not interested in using. 2.7: Classes should only exhibit nil or export coupling with other classes. 2.8: A class should capture one and only one key abstraction. 2.9: Keep related data and behavior in one place. 2.10: Spin off non-related information into another class (i.e. non-communicating behavior). 2.11: Be sure the abstraction that you model are classes and not simply the roles objects play. Chapter 3: Topologies of Action-Oriented Vs. Object-Oriented Applications 3.1: Distribute system intelligence horizontally as uniformly as possible, i.e. the top level classes in a design should share the work uniformly. 3.2: Do not create god classes/objects in your system. Be very suspicious of an abstraction whose name contains Driver, Manager, System, or Subsystem. 3.3: Beware of classes that have many accessor methods defined in their public interface, many of them imply that related data and behavior are not being kept in one place. 3.4: Beware of classes which have too much non-communicating behavior, i.e. methods which operate on a proper subset of the data members of a class. God classes often exhibit lots of non-communicating behavior. 3.5: In applications which consist of an object-oriented model interacting with a user interface, the model should never be dependent on the interface. The interface should be dependent on the model. 3.6: Model the real world whenever possible. (This heuristic is often violated for reasons of system intelligence distribution, avoidance of god classes, and the keeping of related data and behavior in one place). 3.7: Eliminate irrelevant classes from your design. 3.8: Eliminate classes that are outside the system. 3.9: Do not turn an operation into a class. Be suspicious of any class whose name is a verb or derived from a verb. Especially those which have only one piece of meaningful behavior (i.e. do not count sets, gets, and prints). Ask if that piece of meaningful behavior needs to be migrated to some existing or undiscovered class. 3.10: Agent classes are often placed in the analysis model of an application. During design time, many agents are found to be irrelevant and should be removed.