1. [iterative software development] "SOS" principles: (1) Source Code Representation: Express the design in a programming language, not in pictures or a separate specification language. It imposes less on the programmer to learn, makes iterative development efficient and consistent by allowing the output from the previous iteration to be used as the input into the next iteration, and leads to fewer errors in translating the specification. (2) Outside-In Development: Start with the use/test scenario, and develop the interface design, and proceed to the class implementation phase. It causes the use/test scenarios to be specified concisely early on, facilitating fulfillment and understanding of the true requirements, allows class implementation to proceed in parallel, and simplifies integration. (In particular, separation of interface and implementation enhances client simplicity and clarity by requiring the programmer to only read and understand the interface, allows multiple implementations of an interface transparently, and minimizes recompilation.) (3) Short-Cycle Development: Use multiple short cycles rather than fewer longer cycles. It simplifies the cycles by avoiding uncertainties of long cycles, provides quicker feedback to the developers, provides a broader set of choices of product release points, allows better people management, adapts better to subsequent changes, and eventually leads to a good design. 2. [semantic restrictions on accessors and mutators] Any three of the following will get full credit. (1) nilpotent [accessors]: Calling the accessor has no effect on the external state of the object. It allows reads to be satisfied from cached object state, and allows a value to be read repeatedly without concern for some unintended side effect. (2) idempotent [mutators]: Writing the current attribute value has no effect; i.e. calling the mutator with the same value multiple times has the same effect as calling it once. A write operation over a network may be lost, causing the write to be reissued. Without idempotency, this situation could cause subtle bugs. Idempotency also simplifies the event notification model. (3) transactional [accessors]: An accessor returns a consistent value at a given instance in time. Otherwise, particularly in a distributed and concurrent environment, an external state that does not fulfill the object's invariant may be revealed, causing subtle bugs. (4) transactional [mutators]: A mutator sets the attribute atomically to the specified value if it succeeds and otherwise the attribute state is logically unaffected. Otherwise, it may leave the object in some inconsistent state, making it difficult to deal with the object further. (5) exception-free [accessors]: An accessor never throws an exception but returns a default value instead. Trying to propagate an exception in a distributed environment is challenging, and clients may not be able to recover from exceptions, recovering the state of objects, if accessors are allowed to throw an exception. 3. [separating state from processing] We were looking for notifications for onRecording and double-dispatch/visitor pattern for print. Mentioning only one of these methods will get you half points. More specifically, for notifications: class Sensor : public NamedInterface { public: class Notifiee : public BaseNotifiee { virtual void onReconfig(Config *) {} } }; class GpsReactor : public Sensor::Notifiee { public: void onReconfig(Config * config) { /* do something for gps here */ } }; class ImuReactor : public Sensor::Notifiee { public: void onReconfig(Config * config) { /* do something for imu here */ } }; And for double-dispatch/visitor pattern: class Sensor : public NamedInterface { public: void operator( PrintFunctor * f) { f->operator()(this); } }; class PrintFunctor : public NamedInterface { public: virtual void operator()(Gps* ); virtual void operator()(Imu* ); }; 4. [call-up notify-down] a. Any sort hardware/software example would work. Taking an example from the notes, imagine some specialized graphics hardware that could move a cursor directly (rather than redrawing the cursor pixel by pixel.) In a call-down, notifiy-up model, the machine indepdendent code would need to conform to the lowest common denominator hardware and send pixel redraw commands rather than using the optimized functions. Using a call-up, notify-down model, the hardware can samply be notified by the machine indepdendent code when the cursor moves. The hardware can then call accessors to determine where the new location of the cursor is and then decide how best to redraw it. b. There are three main advantages: Simplicity: There is no need to design a broad and generic hardware abstraction layer that tries to capture the capabilities of all hardware. The machine independent code usually also has this interface already designed, so it can simply be reused. Efficiency: By using a call-up approach, the device-specific code can call up into the world to look at the state and then decide what is the most efficient way to implement the changes in hardware. With optimized hardware, this would be much faster than being forced to resort to always using primtive calls. Also, in a call-up approach, you are always calling inline functions for accessors rather than virtual method calls for call-down (because you don't know what kind of hardware you will be calling down into) so you save one level of indirection. Portability: The call-up approach avoids the problem of mapping HAL primitives to actual hardware capabilities, especially when efficiency is a concern. Complex bridging code may be required to transform several HAL primitives into a single high-level operation that the hardware supports. 5. [entity types and value types] a. In the entity approach, each entity represents a single snail or bacteria. In other words, an entity refers to an actual object in the referrant system that one is simulating. The value approach is abstracting the collection of snails and bacteria into an abstract collection that only saves the cardinality of snails and bacteria in a grid block. b. A named description describes a set of objects, rather than an individual entity. It has identity and can be referred to by pointer, but does not represent a real object in the referent system. A named description is also similar to value types since it effectively is a set of values (ie the objects). Two descriptions are equal if they describe the same set of objects. For this question, we were looking more for a description of named descriptions and in what cases they would be appropriate rather than whether or not it would be appropriate in this case.