interfaces

why they are important and why you should pay close attention to interface definition

Gergő Pintér, PhD

gergo.pinter@uni-corvinus.hu

an interface is a shared boundary across which two or more separate components of a computer system [1]

hardware interfaces by Pittigrilli | CC BY-SA
user interface KDE Plasma 5.22 from Wikimedia CC BY-SA

interface is an agreement

  • how a module / component will work
  • so as long as the agreement is complied the components do not need to know about the internal structure/work of the other components
    • separation of concerns
    • single responsibility principle

hexagonal arcitectural pattern (a.k.a. ports & adapters)

user statistics example - interfaces

data sent to the UI

specify
  • the JSON schema
  • endpoint
  • etc.

user statistics - C4 component

interface mocking

  • an interface is a boundary where a module can be separated
  • in the user statistics example there are two parts: a backend and a frontend
  • with a well defined interface, the frontend can work regardless of the backends’s state
    • e.g., using a mock backend

A mock, in software engineering, is a simulated object or module that acts as a stand-in for a real object or module [2].

user statistics - mock backend

require 'sinatra'

def generate_progress
  rand.round(2)
end

def generate_activity_matrix
  result = []
  (1..4).each do |_w|
    daily = []
    (1..7).each do |_d|
      daily.push rand(10)
    end
    result.push daily
  end
  result
end

get '/user-statistics' do
  data = {}
  data['name'] = 'Marvin'
  data['id'] = 42
  data['registration'] = '2019-10-02'
  data['progress'] = generate_progress
  data['activity'] = generate_activity_matrix
  return data.to_json
end

http://localhost:4567/user-statistics

{
    "name": "Marvin",
    "id": 42,
    "registration": "2019-10-02",
    "progress": 0.92,
    "activity": [
        [4,9,7,4,7,1,8],
        [9,8,1,8,4,1,7],
        [3,6,8,4,2,4,5],
        [3,5,5,3,2,9,7]
    ]
}

frontend development

a mock backend should be enough for a frontend developer to create and test the user statistics view of the user interface

{
    "name": "Marvin",
    "id": 42,
    "registration": "2019-10-02",
    "progress": 0.92,
    "activity": [
        [4,9,7,4,7,1,8],
        [9,8,1,8,4,1,7],
        [3,6,8,4,2,4,5],
        [3,5,5,3,2,9,7]
    ]
}

it may be presented to the customer

fast feedback, agile, and so on…

do not change the interface (without notice)

float: 0–1
integer: 0–100

this will break the frontend

it is not just rude, but will waste the time of the other team (with pointless debugging)

do no break the userland

the number one rule of kernel development is that “we don’t break users”

Linus Torvalds

API changes should be communicated

  • during design / development
    • change can be necessary / allowed, but communicate towards the impacted teams
    • diagrams show inner dependencies
  • services announce API deprecations
  • so as library / framework developers
    • can be a source of new issues even if downstream code is not changed

API versions

  • 2021-06-30: API v1’s end of live
    • service does not accept connections via APIv1
    • code can be removed (no need to maintain it anymore)

https://developers.facebook.com/v21.0/me?fields=id,name

language level

GeoPandas 1.0 / new deprecations: unary_union attribute is now deprecated and replaced by the union_all() method (#3007) allowing opting for a faster union algorithm for coverages (#3151)

from shapely import Polygon
import geopandas as gpd

p1 = Polygon([[1, 2], [3, 2], [3, 4], [1, 4]])
p2 = Polygon([[2, 3], [4, 3], [4, 5], [2, 5]])

gpd.GeoDataFrame(geometry=[p1, p2]).unary_union

DeprecationWarning: The ‘unary_union’ attribute is deprecated, use the ‘union_all()’ method instead.

def unary_union(self):
    warnings.warn(
        "The 'unary_union' attribute is deprecated, "
        "use the 'union_all' method instead.",
        DeprecationWarning,
        stacklevel=2,
    )
    return self.union_all()

java

public class Worker {
    /**
     * Calculate period between versions
     * @deprecated
     * This method is no longer acceptable to compute time between versions.
     * <p> Use {@link Utils#calculatePeriod(Machine)} instead.
     *
     * @param machine instance
     * @return computed time
     */
    @Deprecated(since = "4.5", forRemoval = true)
    public int calculate(Machine machine) {
        return machine.exportVersions().size() * 10;
    }
}

source: [3]

IDEs can parse the deprecation decorators and show to the developer during work

a 327 Million Dollar interface miscommunication

NASA and Lockheed Martin mixed up units for the Mars Climate Orbiter (1999)

  • spacecraft sent values back to Earth in Newton seconds
  • the software in the ground station read those results as pound seconds
    • the guidance and navigation teams was off by a factor of 4.45 times
  • this led to a miscalculated trajectory, which doomed the probe and the mission
rendering of the Mars Climate Orbiter by NASA/JPL/Corby Waste via Wikipedia [4]

based on [5], read the full story written by Tim Dodd

references

[1]
Wikipedia contributors, “Interface (computing) — Wikipedia, the free encyclopedia.” https://en.wikipedia.org/w/index.php?title=Interface_(computing)&oldid=1244878409, 2024.
[2]
GeeksforGeeks, “MOCK (introduction) – software engineering.” https://www.geeksforgeeks.org/software-engineering-mock-introduction/ , 26-Apr-2019.
[3]
H. Ozler, “Java @deprecated annotation.” https://www.baeldung.com/java-deprecated , 02-Jan-2019.
[4]
Wikipedia contributors, “Mars climate orbiter — Wikipedia, the free encyclopedia.” https://en.wikipedia.org/w/index.php?title=Mars_Climate_Orbiter&oldid=1248652445, 2024.
[5]
T. Dodd, “Metric vs imperial units: How NASA lost a 327 million dollar mission to mars.” https://everydayastronaut.com/mars-climate-orbiter/ , 14-Mar-2020.