High-Level Design: A Quick Overview

Steven J Zeil

Last modified: Jan 28, 2020
Contents:

Abstract

High-level design is the process of breaking a large system into smaller manageable pieces that can work together to solve a larger problem.

This lesson presents a quick overview of classification, the dominant approach to high-level design.

1 Levels of Design

Software design is largely deivided into

Architectural Design
global decisions that affect nearly all components of a system.
High-Level Design
the division of a system into modular components
Low-Level Design
the selection of data structures and algorithms to implement an individual component
  • CS361 emphasizes this level of design



In current practice, the primary type of “component” that we seek is the class.

The process of discovering such classes is classification, and that is what this lesson will concentrate on.

2 Modeling Classes

We model classes by focusing on

attributes
the data components that conceptually make up or are “contained” within a class
methods
a.k.a. operations, the things we can to do to object of that class
relations
how does this class interact with the other classes in our design?

2.1 Attributes

An attribute of a class is a data property that is conceptually a part of that class.

For example, we might say that an duration or elapsed time can be broken down into hours, minutes, and seconds. Shown on the right is a UML diagram for a class with those three attributes.

2.1.1 Attributes $\neq$ Data Members

One possible realization of this class would be to indeed represent attributes as data members:

class Duration {
public:
    int hours;
    int minutes;
    int seconds;
}

Most class designers would balk at this however, preferring

class Duration {
private:
    int hours;
    int minutes;
    int seconds;
public:
    ⋮
    int getHours() const {return hours;}
    void setHours (int h) { hours = h; }
    
    int getMinutes() const {return minutes;}
    void setMinutes (int m) {minutes = m; }
    
    int getSeconds() const {return seconds;}
    void setSeconds (int s) { seconds = s; }    
}

Both of these are perfectly reasonable realizations of the idea that “a duration of time has attributes of hours, minutes, and seconds”.

This is another perfectly reasonable realization of that idea:

class Duration {
private:
    int secondsSinceMidnight;
public:
    ⋮
    int getHours() const {return secondSinceMidnight / 3600;}
    void setHours (int h);
    
    int getMinutes() const {return (secondSinceMidnight % 3600) / 60;}
    void setMinutes (int m);
    
    int getSeconds() const {return secondSinceMidnight % 60;}
    void setSeconds (int s);    
}

This implementation might be favored if we expect to do a lot of calculations on durations (e.g., adding times together).

This demonstrates that we can have the logical idea of an attribute that does not reflect the eventual data members. All of these possible implementations are still represented by the same UML diagram.

2.2 Operations

Operations are things we do to/with an object that are conceptually more complex than simple storage and retrieval.

It makes sense, for example, to add one duration to another. E.g., if I listen to a music track that takes 4 minutes, then another that takes 3 minutes and 30 seconds, then I have spent a total of 7 minutes, 30 seconds listening to music. Similarly if I say that one track takes 4 minutes and another takes 30 seconds less than the first, I should be able to compute the acutal duration of the second track by subtraction. I might also want to allow multiplication by an integer so that we could work with concepts like “twice as long as”.

In programming terms, operations will map onto public function members. (It is possible to model private members in UML, but that is generally reserved for the very late states of design.)

It’s possible to have classes that have the same attributes but different operations (and vice-versa).

Another idea of “time” is that of the time of day – a particular instant in time rather than a duration. The attributes are the same, but the operations would be different. It does not make any sense to add one time of day to another – you can’t add 12:30PM to 4:00AM and expect that to actually mean anything. But you might add a duration of 30 minutes to 12:30PM to figure out what time it is if you arrive for an appointment at 12:30PM and have to wait for 30 minutes.

2.3 Relations

So far we have talked about what is “inside” a single class. Relations describe important properties between pairs of classes.

2.3.1 Associations

The most basic form of relation is the association, which is simply any named relationship that we wish to discuss or focus on. We read these connections as meaning

  • there is a TimeOfDay associated with an Event that tells us when the event starts, and
  • there is a Duration associated with an Event that tells us how long the event takes".

Associations are very general, so much so that, without the label identifying what we mean by them, they would be too vague to be useful.

But when it’s time to write the labels for an association, there are a few of labels that occur so often in practice that they merit their own UML visual signal:

2.3.2 Aggregation

This new relation is aggregation, and can be read as “an Agenda is part of an Event” or “an Event has a(n) Agenda”.


As a general rule, aggregation relationships could be rewritten as attributes:

This…

…and this…

…mean pretty much the same thing.


Not all attributes, however, can be rewritten as aggregation.

  • Sometimes we prefer to use the aggregation arrow to make the relationship stand out.

    If we think it’s important to our discussion, we may want to make the relationship more visible.

  • Aggregation is somewhat stronger than an attribute.

    For example, I might be OK with this notion of a Student being an attribute of an ID card.

    But I have a real problem with the idea that a Student is “part of” an ID card. We don’t press students flat and laminate them onto a piece of plastic!

    • Now, late in the design phase, when we are clearly talking about programming language classes rather than real-world constructs, I might tolerate this form of aggregation.

2.3.3 Inheritance / Generalization / Specialization

In many real-world scenarios, we encounter pairs of classes where one class is a specialized form of the other. In programming languages, this is referred to as an inheritance relationship, and could be denoted as an association labeled as “specializes” or (in the other direction) “generalizes”, or, more simply “is a”.

For example, we might say that a Duration is a kind of “time”, and a TimeOfDay is another kind of time.

This diagram, for example, captures the ideas that

  • All variations on the idea of “Time” will have same attributes – hours, minutes, and seconds.
  • Duration and TimeOfDay are specialized forms of Time.
  • Duration and TimeOfDay each have operations that are not common to one another not common to the general idea of Time.

3 Classification

The Object-Oriented design philosophy states that

Every program is a simulation, and the quality of a program’s design is directly proportional to how faithfully it mimics the objects in the world being simulated and the way in which those objects interact.

Object-oriented design is all about designing software whose structure mimics the real world.

3.1 How Do We Discover Classes?

  • We do not invent classes,
  • We discover them by examination of the world in which the software will reside.

Remember, first and foremost, that classes are groups of objects and objects are things.

3.1.1 Look for “Things”

Look through the available documentation on the problem you are trying to solve. Talk to people who work in that world.

Look for the kinds of things (nouns or noun phrases) that get mentioned over and over in discussion the problem area.

  • If you can’t have a meaningful discussion about the problem without mentioning a thing of some kind, that “kind of thing” should be one of your classes.

3.2 How Do We Discover Relationships Among Classes?

Look through the available documentation on the problem you are trying to solve. Talk to people who work in that world.

Look for descriptions of how things interact.

  • Verbs and verb phrases that occur repeatedly in any discussion about the problem are suggestive of operations, particularly when they describe something that is happening or changing.

    “Next we schedule the meeting at the agreed-upon time.”

    “We compute the total time of all the tracks onthe album.”

  • Verbs and verb phrases that describe how things are rather than howthey are changing may be suggestive of relations and/or attributes.

    “The meeting starts at a specified time and lasts for a predetermined amount of time.”

    “The duration of a meeting can be expressed in terms of hours, minutes, and seconds.”

3.3 Keep It Real!

Example: We have been tasked with automating the means by which public library patrons find books in the library.

  • We “know” that we will be using a database to permit searches for books.

  • Nonetheless, it is a mistake to design a LibraryDatabase class.

    • Because no one walks into a library, sees a large box labeled “Database”, and says “Ooo, let me look at that.”

  • Instead we would design a Catalog class.

    • Because many generations of library patrons have walked in to a library, moved to the “card catalog”, and searched though it for relevant books.

      • We discover this class in the real world, and model it in our design.
    • It is entirely possible that the data structure and algorithms used for low-level design of the Catalog will be that same database, but that’s a hidden, private decision.

    • From examination of the physical catalog, we learn that traditional searches have been supported by author, by title, and by subject keyword.

      • This informs our interface design for the Catalog class in a way that might not have been obvious if we jumped directly in with a Database.