Unit 08 · lesson

Use Java Interfaces to Define Integration Contracts

You already know Java interfaces from the prerequisite course. Here, the interface matters because robot software often crosses implementation boundaries: real hardware wrappers, simulation, test doubles, framework components, and eventually external systems such as ROS 2.

The design question is not "what is an interface?" It is:

What capability should the rest of the robot software be allowed to depend on?

Start with the smallest useful contract

interface RangeSource {
  String getId();
  double getRangeMeters();
}

A caller such as:

class ObstacleGuard {
  private final double cautionDistanceMeters;

  ObstacleGuard(double cautionDistanceMeters) {
    this.cautionDistanceMeters = cautionDistanceMeters;
  }

  boolean shouldStop(RangeSource source) {
    return source.getRangeMeters() < cautionDistanceMeters;
  }
}

now depends on a capability rather than one concrete sensor class.

That lets the same rule operate against:

  • a hardware-backed wrapper;
  • a simulated source;
  • a deterministic test source;
  • a future adapter that receives values from another subsystem.

The contract is narrower than the implementation

A concrete source may know about CAN IDs, device configuration, timestamps, calibration, or transport details. ObstacleGuard does not need those responsibilities.

That separation gives us an architectural boundary:

producer implementation
→ RangeSource contract
→ decision logic

The caller is allowed to assume the methods exist and satisfy the documented software contract. It is not allowed to assume where the data came from unless the contract says so.

A Java interface does not prove a ROS integration path

This is critical for this bridge.

Suppose you create:

class RosRangeAdapter implements RangeSource {
  // implementation omitted
}

The class name does not prove that ROS 2 data is actually arriving.

To defend a Java-to-ROS integration claim, you would need evidence of the implemented transport boundary itself, such as:

ROS 2 endpoint / process
→ bridge or adapter mechanism
→ Java-visible value
→ RangeSource implementation
→ downstream Java behavior

Without that observed path, the strongest defensible statement is only that the Java software contains an adapter-shaped abstraction.

Contract shape and evidence shape are different

The interface:

interface RangeSource {
  String getId();
  double getRangeMeters();
}

can enforce method signatures at compile time.

It does not guarantee:

  • the range is physically accurate;
  • the value is fresh;
  • the source is hardware-backed;
  • the source is a WPILib subsystem;
  • the source is a ROS 2 node;
  • Java and ROS 2 exchanged data;
  • transport QoS is compatible;
  • a motor responded safely.

Those are separate evidence claims.

Design for substitution without inventing integration

Implement two concrete sources:

class FixedRangeSource implements RangeSource {
  private final String id;
  private final double rangeMeters;

  FixedRangeSource(String id, double rangeMeters) {
    this.id = id;
    this.rangeMeters = rangeMeters;
  }

  public String getId() {
    return id;
  }

  public double getRangeMeters() {
    return rangeMeters;
  }
}

and one second implementation of your choice, such as a simulated changing source.

Then pass both through the same ObstacleGuard logic.

The evidence supports this claim:

The Java decision logic depends on the RangeSource contract and can operate with multiple implementations.

It still does not support this claim:

The Java robot application is integrated with ROS 2.

Integration boundary exercise

For each dependency, decide whether it belongs inside the interface, behind an adapter, or outside the contract entirely:

  • current range in meters;
  • stable source ID;
  • CAN firmware update;
  • ROS topic name;
  • DDS QoS profile;
  • simulation fixture selection;
  • obstacle stop decision;
  • physical motor state.

Defend each choice by naming the caller that actually needs the information.

Evidence artifact

Create a small component-boundary record:

Caller:
Required capability:
Java interface:
Concrete implementation A:
Concrete implementation B:
Evidence that substitution works:
Evidence not demonstrated:

At least one Evidence not demonstrated line must name a ROS 2 or physical-system claim that the Java interface alone cannot prove.

Exit criterion

You understand this lesson when you can explain why a good Java interface can make a future integration cleaner while still providing zero evidence that the integration exists until the transport/runtime boundary is implemented and observed.

That is the distinction Week 9 will use when unit tests exercise robot rules with deterministic sources.