Philip J. Guo - Personal Home Page
Main Menu

Java and Software Engineering Notes

For MIT 6.170 - Laboratory in Software Engineering

by Philip Guo (philip@pgbovine.net)

For the Spring 2006 semester, I was a TA for 6.170, the software engineering laboratory course at MIT. This is a collection of notes about software engineering concepts and Java programming that I have compiled from emails and feedback that I have sent to students in my recitation.

General Java 1.5 Coding Style Tips

Java 1.5 Standard Library Tips

Don't re-invent the wheel. Java has a great standard library that provides tons of functionality. Many of you implemented your own versions of common operations, especially on lists. Before you do that, read the Java 1.5 Standard Library API for the classes of interest (and their super-classes); chances are, there will be some method or combinations of methods that accomplishes what you want to do. Well-written code should contain lots of calls to the Java Standard Library instead of to your own hacked-up versions of methods.

Abstraction Functions

Your abstraction function must explicitly mention ALL of your specfields! It can't just be some informal description of what the class is supposed to represent. Informal descriptions belong in regular comments or in the class overview, not in abstraction functions.

The easiest two-step way to write an abstraction function:

  1. Write down "AF(r) = ADT x such that:", but replace "ADT" with some description of your ADT.
  2. For every specfield, write one line that maps some combination of your object r's concrete fields (e.g., r.foo, r.bar, etc...) to that specfield's value. That is, how could I combine concrete fields of r to get the specfield?

That's it! e.g., for a class Money, let's say:

@specfield amount : real

private int dollars;
private int cents;

Then here is an example of an abstraction function:

AF(r) = Money m such that:
  m.amount = r.dollars + (r.cents / 100)

Even if you write your abstraction function in English, make sure to properly disambiguate between concrete fields and specfields. Remember that the abstraction function provides a mapping between combinations of concrete fields to all specfields. Don't leave out any specfields in your abstraction function!

e.g., for GeoPoint, the specfields are:

@specfield  latitude  : real
@specfield  longitude : real

and the concrete fields are:

private int latitude;
private int longitude;

This is an ambiguous and vague abstraction function:

 latitude represents latitude measured in degrees;
 longitude represents longitude measured in degrees

It is not clear which latitude or longitude one is referring to, and it's not even clear that it's a function. Here is a more preferred abstraction function:

AF(r) = some point p on the Earth such that:
  r.latitude represents p.latitude measured in millionths of degrees
  r.longitude represents p.longitude measured in millionths of degrees

Even though this is also written in pseudo-English, it is now clearly a function from a concrete representation to an abstract state.

Representation Invariants

Be very nitpicky when writing your rep. invariants. Here is my suggested way for doing it:

Examine EVERY concrete field and try to pick out what properties MUST be true about each field and its relationships with other fields. For fields that are not primitives, do they have to be non-null? If so, that's part of the rep. invariant. You don't need to repeat the rep. invariant of a field whose type already has a rep. invariant written for it (ahh, the power of induction).

You should write down rep. invariants even for states that are disallowed by the preconditions of the public constructors. For instance, recall GeoSegment:

public class GeoSegment {
  ...
  private final String name;
  private final GeoPoint p1;
  private final GeoPoint p2;

  /**
   * @requires name != null && p1 != null && p2 != null
   * ...
   **/
  public GeoSegment(String name, GeoPoint p1, GeoPoint p2) {
    ...
  }
}

A reasonable rep. invariant is that name, p1, and p2 cannot be null, but some of you purposely didn't write that down because you figured that any valid GeoSegment must be created with those fields non-null because that's the precondition (@requires) of its only public constructor. However, simply stating in comments that something cannot be null doesn't mean that the code will honor that promise. The whole point of a rep. invariant and accompanying checkRep() is to catch errors in your code. What if your constructor had a bug in it that didn't properly initialize name, p1, and p2? Then the rep. invariant should be violated, and the checkRep() should fail.

Tips for writing and using the checkRep() method to check rep. invariants:

Avoiding Representation Exposure

Code Efficiency

The main focus of 6.170 (and of most real-world software engineering) is on building reliable, maintainable, robust software systems, not squeezing out every ounce of performance possible. As my fellow TA Matthew puts it, computers double in speed every 18 months, but humans don't ever double in speed. What he means is that programmer time is much more valuable than machine time. If you have to make a piece of code more complicated and thus more likely to be buggy just to (hopefully) get some performance gains, then it's not worth it.

The only time you should think about optimizations is after you've already built up a working system along with a test suite. Then you can profile your system to see where it's spending most of its time and direct your optimization efforts to those areas. You will have the advantage of both having an already-working version and also a test suite to serve as your safety net. That being said, in later problem sets, you will sometimes have to consider efficiency, but in those cases we will always tell you that speed is one of the requirements. Otherwise, you should strive to write the clearest code possible.

A general rule of thumb is to never make a design decision that makes your code more complicated for the sole purpose of improving run-time performance.


Last modified: 2006-03-07