Skip to main content

CS 3100: Program Design and Implementation II

Final Review

©2026 Ellen Spertus, CC-BY-SA

Poll: How much of the practice final did you do?

A. None yet

B. I've skimmed it

C. A few problems

D. Many problems

E. All problems

Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Poll: How prepared do you feel for the multiple-choice questions?

Poll image
Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Click below the faces if you haven't tried them yet.

Poll: How prepared do you feel about the case studies?

Poll image
Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Click below the faces if you haven't tried them yet.

Note: You can leave after completing the survey and still get participation credit if you want to complete the practice final before seeing solutions (which will be recorded).

Question 1

The SceneItAll IoT hierarchy from lecture is:

IoTDevice              <<interface>>
└── BaseIoTDevice <<abstract>>
├── Fan
└── Light <<abstract>>
├── SwitchedLight
└── DimmableLight
└── TunableWhiteLight

Consider this code:

Light light = new TunableWhiteLight("living-room", 2700, 100);
((DimmableLight) light).turnOn();

TunableWhiteLight overrides turnOn(). Which version of turnOn() is called?

Draw a Picture Before Viewing Choices

Which version of turnOn() is called?

A. DimmableLight's turnOn(), because the cast changes the runtime type of light to DimmableLight

B. Light's turnOn(), because Light is the declared type of light and static dispatch resolves to it

C. A compilation error occurs because you cannot cast a Light reference to a DimmableLight subtype

D. TunableWhiteLight's turnOn(), because dynamic dispatch resolves calls using the object's runtime type

Java uses dynamic dispatch, so the dynamic (run-time) type is used.

Light light = new TunableWhiteLight("living-room", 2700, 100);
((DimmableLight) light).turnOn();

Answer is D. Review Lab 6.5 if needed.

Question 2

public class Example {
int x = 10;

public static void printX() {
System.out.println(x);
}
}

What is wrong with this code?

A. x should be public for a static method to access it

B. Static methods cannot reference instance variables directly

C. println cannot print an int

D. x must be declared final before a static method can use it

x is an instance variable. It belongs to instances of Example.

printX() is static, so it has no this reference and cannot access instance variable x.

Answer is B. Review Lab 6.5 if needed.

Question 3

Two versions of SceneItAll store controlled devices differently:

  • Version A: List<Device> — membership tested with a for-each loop
  • Version B: HashSet<Device> — membership tested with contains()

What is the Big-O performance of each?

A. Both are O(n)

B. Version A is O(n) and Version B is O(1)

C. Version A is O(n) and Version B is O(log n)

D. Both are O(1) because Java's JIT compiler optimizes small-collection lookups to run in constant time regardless of data structure

A for-each scan is O(n); HashSet.contains() uses hashing to find the element in O(1) time.

Answer is B. See L37 Performance: Big-O in SceneItAll for complexities you should know.

Hashtables

Meme showing Bender from Futurama saying:
I say 'Use a hashtable.' and 90% of the time, I'm right.'

(But use HashMap, not Hashtable.)

Question 4

In a @NullMarked package, a developer writes the following method:

public String formatIngredient(@Nullable String prefix, String name) {
if (prefix == null) {
return name;
}
return prefix + " " + name;
}

Which statement about this signature is correct?

A. name is assumed non-null because the package is @NullMarked; passing null for name would produce a compile-time warning or error

B. The @Nullable annotation on prefix is redundant because all parameters are nullable by default in Java

C. @Nullable on prefix means the nullness checker will throw a NullPointerException automatically if null is passed

D. Both prefix and name are treated as nullable because @Nullable anywhere in a method signature marks all parameters as nullable

As the name @NullMarked suggests, any types that can have null values are marked @Nullable. Answer is A.

Question 5

Why can you use HashMap in your programs without reading its 2000-line implementation?

A. The Java compiler inlines HashMap's implementation at compile time, so you never need to read it

B. HashMap's specification tells you exactly what each method does, letting you treat it as a single mental chunk without understanding its internals

C. HashMap's implementation is hidden using private fields, so the compiler prevents you from accessing it

D. You don't need to read HashMap because you know it implements the Map interface and all Map implementations behave identically

We can read specifications instead of source code. Answer B is correct.

🦨 Answer D is close to true.

Question 6

List lights = new ArrayList<>(List.of(
new DimmableLight("bedroom", 80),
new DimmableLight("kitchen", 30),
new DimmableLight("bedroom", 50)
));

lights.sort(Comparator.comparing(DimmableLight::getId)
.thenComparingInt(DimmableLight::getBrightness));

System.out.println(lights);

Assuming toString() returns just the id and brightness (e.g., "bedroom/80" ), what is printed?

A. [bedroom/50, bedroom/80, kitchen/30] — sorted by id first, then brightness ascending within the same id

B. [bedroom/80, bedroom/50, kitchen/30] — sorted by id first, preserving original order within ties

C. [kitchen/30, bedroom/50, bedroom/80] — sorted by brightness ascending

D. [bedroom/80, kitchen/30, bedroom/50] — original order, unchanged

Comparator.comparing() sorts by [increasing] id first; thenComparingInt() breaks ties by [increasing] brightness. Answer is A.

Question 7

A developer writes this filter:

devices.stream()
.filter(d -> d.isConnected() && d.getBattery() < 20
&& !d.getType().equals("wired")
&& d.getLastSeen().isBefore(cutoff))
.collect(Collectors.toList());

What refactoring would most increase testability?

Pay close attention to the wording! This is asking about testability.

A. Extracting the lambda body into a named method

devices.stream()
.filter(this::isLowBatteryWireless)
.collect(Collectors.toList());
boolean isLowBatteryWireless(Device d) {
return d.isConnected()
&& d.getBattery() < 20
&& !d.getType().equals("wired")
&& d.getLastSeen().isBefore(cutoff);
}

Question 7 Answers

A developer writes this filter:

devices.stream()
.filter(d -> d.isConnected() && d.getBattery() < 20
&& !d.getType().equals("wired")
&& d.getLastSeen().isBefore(cutoff))
.collect(Collectors.toList());

What refactoring would most increase testability?

A. Extracting the lambda body into a named method

B. Replacing Collectors.toList() with Collectors.toUnmodifiableList() so the result cannot be accidentally mutated by callers

C. Splitting the filter into multiple chained .filter() calls, one condition per call

D. Converting the lambda body into an anonymous class

Complex lambda logic should be extracted into a named method for readability, documentation, and independent testability. Answer is A.

Question 8

A developer writes LoggingList, a subclass of ArrayList that counts how many elements have been added:

public class LoggingList<E> extends ArrayList<E> {
private int addCount = 0;

@Override
public boolean add(E e) {
addCount++;
return super.add(e);
}

@Override
public boolean addAll(Collection<? extends E> c) {
addCount += c.size();
return super.addAll(c);
}

/**
* Gets the count of items added to this list
* (whether or not they are subsequently removed).
*
* @return the number of items added to the list
*/
public int getAddCount() { return addCount; }
}

Both of these JUnit tests pass:

@Test
void countsTwoDirectAdds() {
LoggingList<String> list = new LoggingList<>();
list.add("A");
list.add("B");
assertEquals(2, list.getAddCount());
}

@Test
void countsAddAll() {
LoggingList<String> list = new LoggingList<>();
list.addAll(Arrays.asList("A", "B", "C"));
assertEquals(3, list.getAddCount());
}

What is the problem with LoggingList?

Question 8 Answers

A developer writes LoggingList, a subclass of ArrayList that counts how many elements have been added:

public class LoggingList<E> extends ArrayList<E> {
private int addCount = 0;

@Override
public boolean add(E e) { .. }

@Override
public boolean addAll(Collection<? extends E> c) { .. }

public int getAddCount() { return addCount; }
}

What is the problem with LoggingList?

A. addCount should be static so it is shared across all LoggingList instances
B. The class might no longer satisfy its specification if the implementation of ArrayList changes
C. Overriding both add() and addAll() violates the Interface Segregation Principle because the two methods should be in separate interfaces
D. The class violates the Liskov Substitution Principle because LoggingList cannot be used anywhere an ArrayList is expected

Implementation assumes super.addAll() does not call add(). Answer is B.

Question 9

@Test
public void activatesHeatingWhenBelowTarget() {
TemperatureSensor mockSensor = mock(TemperatureSensor.class);
HVACService mockHVAC = mock(HVACService.class);
when(mockSensor.readTemperature("livingRoom")).thenReturn(65.0);

ThermostatController controller = new ThermostatController(mockSensor, mockHVAC);
controller.adjustToTargetTemperature(72.0, "livingRoom");

verify(mockHVAC).activate("livingRoom");
}

What does verify(mockHVAC).activate("livingRoom") do?

Make Sure We Understand Code

@Test
// This tests whether the heater is turned on when we want to heat room.
public void activatesHeatingWhenBelowTarget() {
// Create a test double for the TemperatureSensor.
TemperatureSensor mockSensor = mock(TemperatureSensor.class);

// Create a test double for the HVACService.
HVACService mockHVAC = mock(HVACService.class);

// Simulate a living room temperature of 65.0.
when(mockSensor.readTemperature("livingRoom")).thenReturn(65.0);

// Create a real ThermostatController using the doubles.
ThermostatController controller = new ThermostatController(mockSensor, mockHVAC);

// Test what happens when we tell a ThermostatController to increase LR temperature.
controller.adjustToTargetTemperature(72.0, "livingRoom");
// Make sure the HVACService's activate() method was called with argument "livingRoom".
verify(mockHVAC).activate("livingRoom");
}

What does verify(mockHVAC).activate("livingRoom") do?

Question 9 Answers

What does verify(mockHVAC).activate("livingRoom") do?

A. It asserts that activate was called exactly once with "livingRoom" as the argument

B. It configures the mock to return a specific value the next time activate is called

C. It checks that mockHVAC was originally constructed using "livingRoom" as a parameter

D. It registers a callback so that a real HVAC system is contacted if activate is called

verify asserts the method was called exactly once with the specified argument. Answer is A.

🦨 You shouldn't be expected to remember "exactly once".

Question 10

public class ScheduledTask {
public void runIfDue() {
if (TimeUtils.isBusinessHours()) {
doWork();
}
}
private void doWork() { /* ... */ }
}

A developer wants to test that doWork() is NOT called outside business hours. What is the fundamental testing problem that prevents the developer from even setting up the test scenario?

A. doWork() is private, so neither JUnit nor Mockito can invoke it directly within a test

B. TimeUtils.isBusinessHours() is a static call and cannot be replaced with a test double

C. The class has no explicit constructor, so Mockito cannot create a mock of ScheduledTask

D. runIfDue() returns void, so there is no return value to assert on in the test

The question is about what happens outside business hours, but we can't control what time runIfDue() detects. Answer is B.

Review L16: Designing for Testability, specifically Controllability. (Observability is also important.)

Question 11

A team adopts a modular monolith where the Submissions module and Grading module communicate only through each module's public API, never querying each other's tables directly. What is the primary benefit compared to an unstructured monolith?

A. It eliminates network latency between modules and allows each module's schema to evolve independently
B. It guarantees independent deployment cycles so each module can be released on its own schedule
C. It preserves clean boundaries that make it easier to extract a module into a separate service later
D. It prevents any single bug from crashing the entire application by running modules in separate processes

Monoliths run on a single computer in a single process. Modular monoliths use good abstraction with clean boundaries. The answer is C.

🐒 You haven't explicitly applied this, although CYB is a modular monolith, which you should know.

Question 12

Pawtograder's Grading Action batches all 100 test results into a single submitFeedback() call instead of one call per result. Which fallacy of distributed computing most directly motivates this?

A. "Latency is zero" — making 100 sequential network round-trips would add significant cumulative delay that a single batch avoids

B. "There is one administrator" — separate calls per result may each be subject to different rate limits or firewall policies

C. "The network is secure" — sending results individually exposes more data at each trust boundary crossing

D. "The network is homogeneous" — individual calls may take different paths and behave inconsistently across network segments

Each network call incurs latency; 100 sequential round-trips multiply that cost, which batching eliminates. Answer is A.

🐒 You haven't explicitly applied this, but we need a way to test you on network fallacies, and we've talked a lot about this.

Question 13

When using a Functions as a Service (FaaS) platform instead of managing your own server, which of the following does the programmer still control?

A. The operating system configuration

B. The algorithm used within the function

C. The physical server hardware the function runs on

D. How the server scales under load

The FaaS platform manages infrastructure, scaling, and the OS — the programmer controls only the function's logic. Answer is B.

🐒 You haven't explicitly applied this, but this was the major point of L21: Serverless Architecture.

The Cloud Deployment Spectrum

A horizontal spectrum of seven cloud deployment models. Each station shows an 8-layer stack (Facility, Power, Network, Hardware, Virtualization, OS, Runtime, App) with orange layers (you manage) and teal layers (provider manages). LEFT: Own Data Center has all orange layers, sweating developer. Moving RIGHT: progressively more teal layers. RIGHT: FaaS has almost all teal, with developer relaxing on a cloud-shaped hammock holding only a tiny fn() function. Legend shows orange=you, teal=provider.

Question 14

A startup evaluates two open-source libraries for a desktop application it distributes to customers. Library A uses the MIT license. Library B uses GPL v3. A senior engineer points out that the GPL is more restrictive than the MIT license. Which accurately describes the licensing risk of choosing Library B?

A. The startup must credit Library B authors in all marketing materials but can otherwise keep its source code proprietary

B. The startup may use Library B freely for internal tools but must pay a licensing fee before any commercial distribution

C. Library B is prohibited from use in any commercial product regardless of whether source code is made available

D. Distributing software that includes Library B requires the startup to release its own source code under the GPL

The GPL requires that any software incorporating GPL-licensed code and distributed to others must itself be released under the GPL. Answer is D.

🦨 This is important to know when creating projects but is heavy on memorization.

Question 15

In one version of CookYourBooks, to scale a recipe to a target number of servings, users must type the target serving count but are not shown the original serving size — they must remember it from the previous screen. Which Nielsen heuristic is violated?

Two-panel illustration. Left: a person happily viewing a recipe app showing 'Serving size: 150g'. Right: the same person looking frustrated at a screen showing only an empty 'Enter number of servings:' field with no serving size visible.

Question 15 Answers

In one version of CookYourBooks, to scale a recipe to a target number of servings, users must type the target serving count but are not shown the original serving size — they must remember it from the previous screen. Which Nielsen heuristic is violated?

A. H6 (Recognition Rather Than Recall) — display the original serving size on the scaling screen

B. H3 (User Control and Freedom) — add an Undo button

C. H5 (Error Prevention) — validate that the target is a positive integer

D. H2 (Match Between System and the Real World) — replace the number field with natural language

Users should not have to remember information from a previous screen — the system should display it for them. Answer is A.

Question 16

In another version of CookYourBooks, recipe difficulty is displayed using colored dots (green/yellow/red) with no text labels or shapes. Which POUR principle is violated?

A. Operable, because users with motor impairments are unable to reliably interact with an indicator that provides no keyboard-accessible target

B. Robust, because the colored dots use a non-standard HTML element that will render differently across Chrome, Safari, and Firefox

C. Perceivable, because colorblind users cannot distinguish the levels if color is the only differentiating attribute

D. Understandable, because the green/yellow/red color metaphor carries different cultural meanings in different regions and contexts

Color alone is insufficient — there should be a secondary cue such as shape or text for colorblind users. Answer is C.

❌ D is also valid, and B could be true. This question is broken.

Question 17

submitButton.setOnAction(event -> {
System.out.println("Submitted");
});
System.out.println("Button registered");

In what order do "Button registered" and "Submitted" appear in the console?

Question 17 Answers

submitButton.setOnAction(event -> {
System.out.println("Submitted");
});
System.out.println("Button registered");

In what order do "Button registered" and "Submitted" appear in the console?

A. "Button registered" first, then "Submitted" when the user clicks — the callback is invoked by the event loop

B. "Submitted" first — the callback runs immediately when setOnAction is called, before registration returns

C. Both run simultaneously on separate threads because JavaFX uses a background event dispatcher

D. "Button registered" first, then "Submitted" immediately after on the same call stack, without waiting for user input


Answer is A. setOnAction registers the callback but does not invoke it — the callback fires later when the user clicks the button.

Question 18

Compare two versions of a CookYourBooks recipe scaling feature:

  • Version A: button handler manually iterates over ingredients and calls ing.scale(factor)
  • Version B: button handler calls model.scale(servings) and then updates the view

Which better follows MVC?

  • Model
  • View
  • Controller

Review of MVC (L29)

In L16 we learned to separate domain logic from infrastructure so code is testable. MVC applies that principle to GUIs:

The Model is cleanly domain-side — no UI imports, fully testable. But the Controller does everything else: it reads from the Model, makes decisions, AND manually pushes updates to View widgets.

Model

Data + business logic. Knows nothing about the UI.

View

What the user sees. Widgets, layout, styling. No business logic.

Controller

Translates user actions into model updates. The thin middleman.

Question 18 Answers

Compare two versions of a CookYourBooks recipe scaling feature:

  • Version A: button handler manually iterates over ingredients and calls ing.scale(factor)
  • Version B: button handler calls model.scale(servings) and then updates the view

Which better follows MVC?

A. Version A, because it gives the Controller direct control over scaling each ingredient

B. Version B, because scaling logic belongs in the Model; the Controller should delegate

C. Version A, because the Controller should perform all computation to keep the Model simple

D. Version B, because bidirectional data binding between Model and View ensures the ingredient list updates automatically

The button handler is part of the View; scaling logic is business logic and belongs in the Model; the Controller's job is to delegate to the Model, not perform computation itself. Answer is B.

Question 19

In MVVM, a test sets a property on the ViewModel and verifies the result without simulating a button click or starting a UI. Why does this work?

What's MVVM? [L30]

Model

Same as MVC. Business logic, no UI.

ViewModel (new)

UI state as bindable properties. No reference to the View. Fully testable.

View

Declaratively binds to ViewModel properties. Contains no logic.

MVVM simplifies View updates and is more testable than MVC.

It's what you've been using in the CYB.

Question 19 Answers

In MVVM, a test sets a property on the ViewModel and verifies the result without simulating a button click or starting a UI. Why does this work?

A. TestFX automatically intercepts ViewModel property changes and triggers bound assertions without requiring explicit verification calls

B. The test bypasses the ViewModel entirely and calls Recipe.scale() directly on the Model, so no UI component is needed

C. JavaFX property bindings are evaluated lazily, so the test assertion runs before the UI thread has processed the update

D. The ViewModel exposes observable properties settable in tests, because it holds no reference to the View

The ViewModel holds no reference to the View, so its observable properties can be set and read directly in tests without any UI involvement. Answer is D.

You should have CYB experience with this. See also Lab 12 and Lecture 30: GUI Patterns and Testing.

Question 20

A DeviceRegistry has private int deviceCount = 0 and registerDevice() does deviceCount++. Ten threads each call registerDevice() once. Why might getDeviceCount() return less than 10?

You Can't Trust deviceCount++ [L31]

Question 20 Answers

A DeviceRegistry has private int deviceCount = 0 and registerDevice() does deviceCount++. Ten threads each call registerDevice() once. Why might getDeviceCount() return less than 10?

A. int is not valid for shared mutable fields; only long or AtomicInteger support safe multi-threaded reads

B. Java guarantees int reads are atomic, so the problem must be a visibility issue from CPU cache coherence delays

C. The JVM silently rounds down concurrent increments for performance, discarding some writes when contention is high

D. deviceCount++ is not atomic — it reads, increments, and writes in three steps, so two threads may read the same stale value

deviceCount++ is three separate operations (read, increment, write), so two threads can read the same value simultaneously and one increment is lost. Answer is D.

Question 21

activateScene() synchronizes on room then device. firmwareUpdate() synchronizes on device then room. Thread A runs activateScene() while Thread B runs firmwareUpdate(). What happens?

Parsing Question 21

activateScene() synchronizes on room then device.

firmwareUpdate() synchronizes on device then room.

Thread A runs activateScene() while Thread B runs firmwareUpdate(). What happens?


eatLasagna() synchronizes on fork then knife.

eatTorte() synchronizes on knife then fork.

Roommate A runs eatLasagna() while Roommate B runs eatTorte() . What happens?

Deadlock

Two roommates glaring at each other across a dinner table, each holding one utensil and reaching for the other. The male roommate has a fork and a plate of lasagna; the female roommate has a knife and a slice of torte. Neither can eat because each is waiting for the utensil the other is holding — a deadlock.

One roommate has the fork and wants the knife; the other has the knife and wants the fork.

Question 21 Answers

activateScene() synchronizes on room then device. firmwareUpdate() synchronizes on device then room. Thread A runs activateScene() while Thread B runs firmwareUpdate(). What happens?

A. Thread B completes first because it acquires fewer locks and thus encounters less contention

B. Both proceed normally because synchronized blocks on different object instances never interact

C. A deadlock can occur: Thread A holds room and waits for device; Thread B holds device and waits for room

D. A race condition corrupts device state because synchronized only protects accesses to primitive fields

Inconsistent lock ordering across two threads creates a circular wait — the classic condition for deadlock. Answer is C.

This can be solved by agreeing on the order in which locks must be acquired.

Question 22

In a CookYourBooks JavaFX app, a button click triggers a database search that takes 2 seconds. A student puts the database call directly in the button's action handler. What happens?

A. The search runs in parallel with the UI on a separate thread automatically created by JavaFX

B. The UI freezes for 2 seconds because the FX thread is blocked waiting for the database

C. JavaFX detects the slow operation and moves it to a background thread automatically

D. The search completes immediately because JavaFX caches database results

The FX Application Thread handles both UI events and rendering — blocking it with a slow database call freezes the entire UI until the call returns. Answer is B.

Instead, the FX thread should start a background thread, ideally with BackgroundTaskRunner.run().

Question 23

In BackgroundTaskRunner, the onSuccess callback always runs on the FX Application Thread rather than on the background thread that produced the result. Why?

BackgroundTaskRunner Signature [L32]

public static <T> Task<T> run(
Callable<T> callable, // () -> fetchRecipe()
Consumer<T> onSuccess, // (String recipe) -> updateUI(recipe)
Consumer<Throwable> onFailure // (Throwable error) -> showError(error)
)

In our example, the type argument T is String.

TypeMeaningThreadExample
Callable<T>A lambda with no arguments that returns a value of type Tbackground() -> fetchRecipe() returns String
Consumer<T>A lambda that takes a value of type T and returns nothingJavaFX(String recipe) -> updateUI(recipe)
Consumer<Throwable>A lambda that takes an exception and returns nothingJavaFX(Throwable error) -> showError(error)

Question 23 Answers

In BackgroundTaskRunner, the onSuccess callback always runs on the FX Application Thread rather than on the background thread that produced the result. Why?

A. The FX thread is faster than background threads for processing data

B. Background threads are terminated immediately after the callable returns, so they cannot run callbacks

C. Running onSuccess on the FX thread enables the callback to update the UI

D. Running onSuccess on the FX thread prevents the callable from being cancelled mid-execution

JavaFX requires that all UI updates happen on the FX Application Thread — running onSuccess there ensures the callback can safely update the UI. Answer is C.

Question 24

BackgroundTaskRunner.run(
() -> loadRecipes(), // takes 2 seconds
recipes -> showRecipes(recipes),
error -> showError(error)
);
log("Ready");

Assuming loadRecipes() succeeds, in what order do these events occur?

A. loadRecipes() runs, then showRecipes() runs, then "Ready" is logged — all on the FX thread in sequence

B. "Ready" is logged on the FX thread, then loadRecipes() runs on a background thread, then showRecipes() runs on the FX thread

C. loadRecipes() and log("Ready") run simultaneously on separate threads, then showRecipes() runs

D. "Ready" is logged, then loadRecipes() runs, then showRecipes() runs — all on the background thread

BackgroundTaskRunner.run() returns immediately, so log("Ready") runs on the FX thread right away; loadRecipes() runs on a background thread, and showRecipes() is called on the FX thread via onSuccess. Answer is B.

❌ C is possible. This question is broken.

Question 25

A developer wants to build a responsive JavaFX application. Which of these operations can be done equally well on either the FX Application Thread or a background thread?

A. Changing the GUI display between dark mode and light mode

B. Cutting power to all devices

C. Calling the Java library routine LocalDateTime.now() to get the time of day

D. Backing up all data to a server

Answer is C. LocalDateTime.now() is a fast, non-UI operation with no side effects — it can safely run on either thread. The others must run on a specific thread: A must be on the FX thread; B and D should be on a background thread.

Some Other Possible Topics

  • Java, especially subtyping, exceptions
  • Specifications (restrictiveness, generality, clarity; javadoc) [L4]
  • Minimizing coupling/maximizing abstraction through clear boundaries
  • All 5 SOLID principles
  • Requirements (stakeholders, values, interests; how to elicit)
  • Domain modeling (use domain-related names)
  • Reading UML static class diagrams
  • Debugging
  • Test doubles (spies, mocks, stubs)
  • Testability and dependency injection
  • Design patterns (static factory methods and builders (EJ 1-2), facade, observer)
  • Creating service boundaries
  • Architectures (hexagonal, monolithic, microservices, serverless)
  • Teams (HRT, accountability)
  • Open source (supply chain risk, different licenses)
  • Usability (stakeholders, accessibility, Nielsen's heuristics)
  • User-centered design
  • Concurrency (Lab 13)

Principles

  • Prioritize readability, changeability, maintainability, etc., over cleverness and micro-optimizations
  • You cannot prove a nontrivial program bug-free
    • Validate as much as possible
    • Minimize harm from errors
  • Software architecture/design is full of trade-offs
  • Use but verify AI; you are responsible for code you submit
  • Finding and fixing problems gets more expensive over time

Poll: Would you come to office hours tomorrow?

I could go over grades and answer questions about material.

Poll image
Poll Everywhere QR Code or Logo

Text espertus to 22333 if the
URL isn't working for you.

https://pollev.com/espertus

Click on the left edge if you would not go.

Announcement: STEM Lunch and Panel

Event: Making STEM Accessible
Date: Friday, April 17
Time: 11:00 AM – 12:15 PM
Location: Cyclone Rec Room (In the student union, across the tea shop)
Hosted by: ASNUO & Khoury College of Computer Sciences

The event is an informal panel designed to explore pathways into STEM and computer science, with a particular focus on supporting women and students from non-traditional CS backgrounds. The format will include light discussion questions and open conversation with attendees. Lunch from Ike's Sandwiches will be provided.

Bonus Slide

Cartoon showing a professor holding a paper in front of a board with 'Advanced Mathematics Theory' on it.
Professor says: 'Today's test is 70% of your final grade
which makes up 35% of your grade for the semester and 20%
of your GPA for 50% of your scholastic career for 15% of the
curriculum. If you can explain this to the person next to you,
you pass the test.'
(c) Randy Glasbergen/glasbergen.com