CSE190L Notes for Monday, 5/21/07
I said that I wanted to briefly talk about the kinds of issues that come up in
cse403,
our software engineering course. We don't have time to cover these topics in
the depth they deserve, but I think it's good for people to be familiar with
the terminology and basic ideas involved. These might also serve as starting
points for people who want to explore on their own.
As far back as the 1970's people were talking about the software crisis
that we were spending huge amounts of money on maintaining legacy software that
didn't work very well and that we seemed to have a problem producing new
software. I showed some slides from Grady Booch, who is one of the
gurus of the field. He quoted some interesting statistics from the Chaos
Report put out by The Standish
Group. In their first report in 1994 their research showed that:
- 16.2% of software projects are successful
- 31.1% of software projects are outright failures
- 52.7% of software projects are challenged
And those were the results after two decades of effort in the field of
software engineering to figure out how to produce better software. In their
terminology, "challenged" projects either end up coming in late, going over
budget or failing to implement all of the features requested.
The numbers for 20006 are better, but still not terribly encouraging:
- 35% of software projects are successful
- 19% of software projects are outright failures
- 46% of software projects are challenged
Booch attributes the improvement to three factors:
- Better project management
- Iterative development
- Emerging Web infrastructure
In the 1990's Grady Booch got together with two of the other major luminaries
in the field (James
Rumbaugh and Ivar
Jacobson). They are collectively known as the "three amigos." They all
ended up working for a company called Rational Software.
Together they defined what is known as the Unified Modeling
Language or UML. UML is used to model various aspects of a computer
system. For example, you can draw UML diagrams of the various classes in a
system and indicate the elements of each class and the interconnections between
classes.
I then talked about a class of software tools for working with UML diagrams.
The most sophisticated of these tools provide what is known as round trip
engineering where you can go back and forth between code and UML, editing
the design in either form. For example, you can start with code and ask for
the corresponding UML, then you can edit the UML diagram and ask that it be
turned back into corresponding code. I demonstrated such a tool called Borland
Together and had it create a UML diagram from the Clicker code we have been
exploring. The industry standard tool for this is from Rational Software and
is called Rational
Rose or "Rose" for short.
I mentioned that a great resource for UML is a book by Martin Fowler called UML
Distilled. Martin has an interesting web page that has links to talks,
papers and a blog that he writes. In the tutorial, Martin had mentioned to us
that he thinks that often it is the case that simpler UML tools can be more
useful, particularly for the casual user. The problem with the round-trip
tools is that it's too automated. It becomes too easy to generate a complex
diagram that might not mean much. It can be advantageous to think it through
yourself and draw the diagrams by hand. I showed another tool developed by
Cay Horstmann called Violet that is
a lightweight tool that allows you to draw UML diagrams.
I spent the last part of lecture talking about design patterns. There are many
online resources for design patterns, so I won't try to reproduce that in these
notes, especially since we just briefly discussed the subject. There are many
resources available from the patterns
homepage. Another good source is the wikipedia page on
design patterns which talks about the "Gang of Four" book that inspired this
movement. One final resource that I would recommend is a page
from Rice University that describes the most common design patterns.
I mentioned that one of the single most useful byproducts of the design
patterns movement has been to create a new vocabulary that allows us to
communicate design ideas more easily. For example, we are using the
Model/View/Controller design pattern for our Qubic solutions and it allows us
to use just three words to describe the overall architecture of our system.
I briefly discussed several design patterns and where they appear in Java
programs:
- Observer: Java has support for this in the form of the Observer
class and the Observable interface.
- Adapter: The analogy here is to something like a power adapter
that allows a device like your laptop to plug into a standard power
outlet. The adapter does any conversion that is necessary. The
listeners we have been defining all quarter are adapters. They implement
standard interfaces like ActionListener and MouseListener (like the
adapter that plugs into a standard power outlet) and they do the work of
translating actions like mousePressed into appropriate actions for the
particular application.
- Iterator: This is probably one of the best known design patterns
and it appears throughout the Java class libraries. There is an Iterator
interface that the major collections classes implement.
- Factory: The most common way to create an object in Java is to
call new or to clone an existing object, but sometimes it is better to
hide the details of how objects are constructed. An object or method
that constructs objects is known as a factory. For example, when you
want a NumberFormat object, you call a static factory method as we did in
assignment #1, calling NumberFormat.getCurrencyInstance(). All we know
about that method is that it returns something of type NumberFormat. We
don't know anything about the details of how it is constructed, what type
it is, etc. This gives greater flexibility to the implementor of the
method, which can be very useful.
- Singleton: This pattern is used when you want to have exactly one
of some object. For example, there is one and only one Runtime object
that can be accessed by your program. This is accomplished by having a
private constructor in the Runtime class, which means that nobody outside
the class can construct one. Inside the class there is a static field
that keeps track of the one and only instance of Runtime. You can only
access this instance by calling Runtime.getRuntime().
- Strategy: The strategy pattern is useful when you want to be able
to define a class of interchangeable algorithms. Our Qubic strategies
are an excellent example. This is normally accomplished by defining an
interface that each strategy implements and making it easy to substitute
anything that implements the interface. An example of this in the Java
class libraries is LayoutManager. A layout manager defines an algorithm
for laying out user interface components. They all implement the same
interface and they are interchangeable.
- Flyweight: This design pattern is useful when you are concerned
about getting lots of copies of some object. This can happen with String
objects. You might have many different String objects that each store
the same text. If your program ends up with lots of duplicates, it can
end up wasting a lot of space. In the flyweight pattern, you keep an
internal database of known objects. Java's String class provides support
for this. Read the documentation for the method String.intern if you are
interested. The bottom line is that if you include a line of code like
this for every String you create, you can greatly improve the memory
efficiency of your program:
s = s.intern();
Stuart Reges
Last modified: Tue May 29 09:11:58 PDT 2007