Home > Articles > Programming

  • Print
  • + Share This
From the author of

Controlling Complexity Though Design

When you have the task of designing a new application, you need to consider all of the things that help make existing software more understandable. After all, once you've created the application, sooner or later you have to revisit the code to add new features or change existing ones. At that point, you'll find out whether you were successful in creating understandable, maintainable code.

To create maintainable software, you really need the help that objects provide. You need to make sure that you design the interactions between the objects in a way that makes the resulting code easy to read and understand. After all, you never want your teammates to hear you cry, "Who wrote this piece of garbage?! I can't make sense of it at all! Oh...it was me..."

Classes Represent Concepts

The first thing to remember when designing your application is to use classes to represent important concepts. How do you know what the important concepts are for your application? Simple. Look at your requirements, use cases, and test cases. The concepts that show up in those are in all probability going to become classes in your application.

For the Running Club Membership system discussed in the last article, here are some candidate classes:

Class

Description

Member

Represents a club member

Club

Represents the club to which the Member belongs (this is a very easy concept to miss, believe it or not)

ClubEvent

The special events that the club secretary wants to tell the members about

Race

A special kind of ClubEvent, against which the members report RaceResults

RaceResult

Represents a member's time and placement in a particular Race


Assigning Responsibilities to Classes

Once you have some ideas for the candidate classes, your next design task is to work through one use case and associated acceptance test cases (see Part 5 of this series, "Creating Acceptance Tests from Use Cases") to assign responsibilities for delivering the various subfunction goals to classes within the application. When initially assigning responsibilities, try to group related responsibilities together in the same class. Don't worry if you identify a responsibility that doesn't fit any of your candidate classes; it just means that you have to invent a new class for that particular responsibility.

As you work through your design ideas, you'll inevitably learn about how your design works, and in the process realign the responsibilities. Indeed, you might find it beneficial to come up with three different initial designs to explore different options. If you do this, you might even discover that the first idea you came up with is not actually the best option.

When looking through the use cases to identify the responsibilities, it's easiest to just read through the main success scenario first. Defer looking through the extensions for responsibilities until after you feel you've correctly assigned the main responsibilities.

For the use case Club Secretary : Notify members about special events, here's one possible assignment of responsibilities:

  • Member: Represents a club member

    • Knows name, email address, and phone number

    • Matches what it knows against specified selection criteria

    • Records delivery of event notification

  • Club: Represents the club to which the Member belongs

    • Knows members and special events

    • Sends event notification emails

    • Prints event notifications

    • ClubEvent: The special events that the club secretary wants to tell the members about

    • Knows name, date, and description of special event

In this design option, the ClubEvent is a data holder object without any really interesting behavioral responsibilities. Another design option would be to have the ClubEvent responsible for emailing itself.

  • + Share This
  • 🔖 Save To Your Account