|
12.4. Finding the ObjectsThe basic technique for doing OOA[1] with CRC cards is to start with a stack of blank cards. Assemble a design team (this may be one person, or this may be dozens).[2] The first step should always be the nomination of the real-world objects. Don't edit or critique at this point. If someone says "computer" as an object, write "Computer" on the top of a card and put it on the table. If someone says "Manager" write it on a card and put it on the table.
To take our example, suppose we have the following list of CRC cards after such an open brainstorming session:
Where do you go from here? Let's articulate a general principle. The first principle. If we could teach a programmer only one thing about software design, it would be this idea: less is more. Or, to quote Antoine de Saint-Exupéry: "Perfection is achieved not when nothing can be added, but when nothing can be taken away." Or, to put it yet another way, always use the KISS[3] principle. The best object design is the smallest possible number of classes that model the real objects and meet all the requirements.
You are seeking simplifying abstractions. First of all, all the objects that represent technologies or implementation details should be removed. In our list, this would include "Database," "Computer," and "Keyboard." While it is likely that all three will be involved in the final product, they are not objects in the problem space. There is no theoretical reason why an OOA session cannot produce a manual, noncomputer solution. It is a common tendency to leap from problem analysis directly to technical solutions. "We can write that in Java," "We can store those in Oracle," "That could be an XML file." Statements like these are to be avoided at this stage. Those are details about the implementation. You haven't got a design to implement yet! As we said, you are seeking simplifying abstractions. The next step, after culling cards that do not represent real objects in the problem space, is to group together the cards that have any attributes in common. If we look at our remaining cards, we can quickly see that we have two cards that are accounts: "Capital Account" and "Current Account." These are both pools of money. Put them on top of one another on the table. Likewise, it is fairly obvious that "CEO," "CFO," "Director," and "Manager" are all people. Put them together on the table. Remember that we are looking for simplifying abstractions. The grouped cards should all be obviously variant types of a generic class of objects. In our example, the one is a stack of Accounts, and the other is a stack of People, or, as we will call them, Users. Create new cards for these generic classes. Make a card with "Account" at the top and put it above the first stack. Make another card with "User" at the top and put it above the second stack. There are two ways that this might simplify your design. For now, all cards below the abstract cards are "on probation." We are going to move on to define the attributes (data) and methods (behavior) of our abstract classes. If the abstract class can handle all use cases without having to treat any of the more specific classes differently, then the specific cards are discarded. If not, then all functionality that is common across the more specific types will be put on the abstract class card, and only those data and behaviors that are different will be put on the more detailed cards. In the first case, the simplification is a reduction of several potential classes to a single class. This is always a good thing, when it is possible. In the second case, you are identifying potential inheritance relationships. [4]
|
|