Software Engineering Lecture 2
is a way of thinking about a set of
interconnected things that work together.
Systems are composed of
pieces which are also systems by themselves.
Examples of systems you know:
The Solar System
your body’s nervous system
your computer’s operating system
The power of using the idea of a “system” is that
it allows us to take something very complicated
and break it into pieces that work independently.
If we couldn’t do this with software, we couldn’t write
This simplification of how we view things in a
system is called
. It’s a goal
level view of things, rather than becoming
immersed in the details.
things are broad descriptions or
concepts useful for understanding what
something does. An abstract description of what
a car does might be, “it’s a small motorized
device used to transport people and goods”.
things are specific details in which the
overall purpose of the system can get lost. A
concrete description of a car would be complex!
When we use computers, what we want is
something abstract, not concrete:
Communicate a message
Answer a math problem
Make horrific pornography appear on the screen
We don’t often care about the
of how this
gets done. (Nobody runs a program in order to
set the zeroes and ones to a particular value.)
However, we sometimes have no choice but to
care about concrete details.
Someone has to
a car before you can drive it!
There are two
that we think in, depending
on whether we are handling the abstract details
or the concrete details:
: the user of something (abstract view)
: the designer or fixer (concrete view)
In software, you play
at the same time
You are a
of a class any time
an object of that class type.
You are a
of an operation any
You are an
of a class or
operation when you
code that makes it function properly.
thinking like a client
of a system,
you’re thinking in
For example: when I go to pour a glass of water
from the sink, I don’t immerse myself in thinking
the faucet works. Instead, I just use
the faucet gives me (
) to get the
I want. I’m focused on
only what I must do
to get there.
thinking like an implementer
system, you’re thinking in
If I’m repairing a faucet, I need to understand
how it works. The
now matter, because
my goal has changed
. I’m not trying to
system, I’m trying to
it…and to fix it, I need to
make it work.
Implementers don’t need to focus on how the
work! A plumber needn’t know how
plumbing pipes are
, as long as they know
them (as a
!) to make repairs.
In other words, an implementer
looks at the
whole system concretely
, in terms of its pieces.
But when you do this, you
think about the
, as a client! Otherwise,
you’d be overwhelmed by the information.
Any time you
an operation or
, however! The
code inside the body of an operation or
component is its implementer code.
So it’s not like some section of code is
. Different places in code are client
or implementer of
different operations and
In order to write large software, we need to
design things so that code in one place won’t
break code in another place when it changes.
The way to do this is to divide code up into
. In object
are chiefly the
(i.e., definitions for new data types).
We need to separate these components with
, for safety.
To facilitate component
separation, we use something
goal is to take the data that
represents something and hide
it from the
Instead of accessing the data
directly, the client will rely on
that we provide them.
In order to hide information, implementer code
must replace the hidden information with
something else the client can understand.
is the process of simplifying data
access by providing a conceptual description or
“cover story” which leaves out implementation
details. The description tells a client
So, when we design a class, we really want to
(surrounding by an
abstract barrier) the
, and include
works on the data. This code will allow the client
to manipulate the data indirectly, from an
specifications for code
we use to access
hidden data are called an
. (The word
special meaning in Java.)
Cars have a well
: a gas pedal, brake pedal, steering
wheel, gear shift, lights, and the turn signal that
most assholes don’t seem to understand exists.
But this interface is highly
! Cars don’t
give you access to any of the
. There’s no
knob that lets you change the rate at which fuel
is injected, or how fast the pistons fire.
But this is a
! If we did have access to
such details, think about what might happen:
I would most certainly destroy my goddamn car.
I’d have to take classes in engineering,
just to drive
The way my car drives may not translate to other cars.
If my car gets repaired, I might need to
restricting what we have access to
one of the most powerful tools we have
Strange as it seems,
ignorance is empowering
Since I don’t need to know these details, that
abstract car interface gives me four benefits:
my car (as easily).
don’t need to learn
as much to drive.
: I can drive
anyone else’s car
: If my car changes, I can
* Provided it has
the same interface
(e.g., not a stick shift).
, we see the same
benefits when we
and protect data
by relying only on
less likely to misuse
easier to learn
to use the component.
: You can
change or choose
component version you’re using,
even at run
: Changing how the component works
other components. This is
(engine, wires, gears)
is responsible for
storing and interpreting its
objects’ data. Users don’t
need to know how it works!
(steering, gas, brake)
(user) of an object
the object to access and change
its value. The data is
The user doesn’t need to know
the object works. They
should think about the object
, in terms of what its
expected behavior should be
There’s a difference between
“a public interface to an encapsulated object”,
, which is a very particular
kind of abstract Java component.
However, Java interfaces are
the interface concept: they’re the best place to
our public interface to an object type.
Java classes come in three flavors of abstraction
(sometimes just called
the only class types you can make objects of, by using
operator. These are totally
type in Java. They can’t have
concrete code (apart
from constants), so they basically hold… interfaces!
. You can’t make
objects from them, but they may still contain code.
When designing code, you want components to
the most abstract descriptions possible
This makes your components
easier to use
flexible to change
We’ll look at this in
more detail later on.
There’s an important idea we’ve mentioned a
few times now: reliance on
(abstract view) rather than on
In order for this to work, we need an
between the client and implementer: a
that tells us what we need to use the component.
does this operation (or class)
can we assume it will work?
This approach, where the user of a system relies
on specs rather than how code is written is called
. It’s what makes the
creation of large software systems possible.
DBC is also known as “programming
o the interface”.
A contract (i.e. specifications) need not cover
every situation! Requirements can be placed on
the client. For example, the operation of your car
is not guaranteed if you turn it off while racing.
is a description of the
under which an operation will
actually work correctly.
(the code that
calls the operation
only guaranteed the operation will do
the precondition is met!
is the one who must check
preconditions before calling an operation.
is a description of what the
is responsible for making sure
the code actually fulfills this specification.
However, an implementer should freely
has been met, since the
guaranteed to work when it’s true.
Not assuming this can lead to
this can hide errors from you during testing.
By not double
checking, code may be much
easier to write. You can leave
check your preconditions when coding
, and after
testing, remove them for better performance
and improved error
When you’re testing, however, you
preconditions to explode the program as openly
as possible! A failed precondition means your
isn’t written properly
Note that assert statements do not contradict
design by contract principles!
These statements are here to ensure when you
fail an assert during testing, you immediately are
aware of where the problem is and what you did
wrong (essentially, your code violated a
These don’t need to be compiled in
(after testing), but only in
You might wonder: is it always a good idea to
place the onus of checking on the user of a
component? What if you miss something during
will that become unrecoverable error?
Code can be written to be fault
tolerant, yes. But
you really want to catch misuse of a component;
the contract may not even make sense if you
violate it. Just realize that for the
precondition should be simple (if not always true).
The contracts we’ll use in this class are rather
in nature, which isn’t something you’ll see
in industry (at least, not anytime soon).
The good news is this: if you can actually read
mathematical language, formal contracts are
! (Since every computer
scientist should be able to read math, we don’t
think this is an unrealistic expectation.)
In keeping with this mathematical formality,
every kind of object will have an underlying
that describes its behavior.
We’ll cover this in depth later, but really all you
need to understand are
(the mathematical kind),
. We’ve already covered the former four
and we’ll discuss the latter four later on.
Our contracts will appear in
are special comments that create
documentation automatically. You can (and
should!) place one before each class, method, or
data member (class or instance variable).
are entered just like multi
comments, except they start with
asterisks rather than just one).
Our contracts will contain
which identify the parts of a specification:
precedes a description of the
also describes what a function
returns by using the name of the function itself.
specifications on methods will also
for each parameter.
This will be necessary when we start working
mutable reference types
, because a big
part of what any method does will involve what
happens to the objects to which it was passed a
We’ll discuss this later when the subject arises.
The client code
preconditions of the
methods it uses; the implementer code
its preconditions are true!
Similarly, client code
that the post
condition (the thing the method should do)
actually happens after the call. The implementer
This is a commonly missed test question…