Live data from Hacker News

Designing Good Interfaces

pboyd.io

11–20 of 32 posts

Re: Designing Good Interfaces

#11
post #6

Good interfaces should primarily have reasonable and well documented pre and post conditions. This is very apparently not so in the oil change example in the article. It's completely stunning to me how frequently this is forgotten in spite of having been a key component of object oriented programming when it was invented (ie smalltalk days, before I was born).

Can you clarify what you mean by this?

For instance, does the old oil need to be drained before filling new oil?

Does the car need to be checked for leaks?

At the end of filling in new oil, how much oil should be in the car? How much left over?

Re: Designing Good Interfaces

#12
post #6

Good interfaces should primarily have reasonable and well documented pre and post conditions. This is very apparently not so in the oil change example in the article. It's completely stunning to me how frequently this is forgotten in spite of having been a key component of object oriented programming when it was invented (ie smalltalk days, before I was born).

Can you clarify what you mean by this?

Sure, here are some postconditions for ChangeOil():

- engine has appropriate amount of oil in it

- oil filter in place

- drain plug torqued correctly

- dip stick present

- oil cap on

No matter what the outcome of the operation (ie error paths or happy path), ChangeOil promises to return with the car in a state that fulfills those conditions.

In order to do that, some preconditions need to be fulfilled too:

- car has some amount if oil in engine

- car is able to start

- no major noises

Re: Designing Good Interfaces

#13
post #6

Good interfaces should primarily have reasonable and well documented pre and post conditions. This is very apparently not so in the oil change example in the article. It's completely stunning to me how frequently this is forgotten in spite of having been a key component of object oriented programming when it was invented (ie smalltalk days, before I was born).

Is this what we refer to as design by contract?

If so, what about invariants? Are invariants related to good interface design?

Re: Designing Good Interfaces

#14

Most of the post resonated with me, but the initial analogy and its concrete example give me pause. > The dependency (oil, in this example) is an argument, not because anyone cares to customize it, but to simplify the implementation. This is a huge leap ! I know it’s an example, but it’s perfectly reasonable to satisfy both “don’t make me bring oil to the grease monkeys” and “express oil as an explicit dependency of…

It seemed to me that the whole example was too contrived. The garage could simply have the option to buy the oil and give it to the mechanic.

    func GetOil(oilType OilType) Oil {
        ...
    }

    func ChangeOil(c Car, oil Oil) error {
        ...
    }

Re: Designing Good Interfaces

#15
An interface is a contract. It shouldn't be concerned with implementation details and it should contain the absolute minimum to do the work.

public ResultType ChangeOil(Car c, Oil oil = null); is enough.

In the actual implementation of the interface we can check if oil is null and if it is, provide own oil which fits car. If oil is not null, we can check if it is enough and if the type fits car type.

We also can return a car with changed oil and an error.

However the user of the interface shouldn't be concerned with actual implementation details. The same way an user of a Web API shouldn't be concerned with actual implementation detail.

Re: Designing Good Interfaces

#17

Most of the post resonated with me, but the initial analogy and its concrete example give me pause. > The dependency (oil, in this example) is an argument, not because anyone cares to customize it, but to simplify the implementation. This is a huge leap ! I know it’s an example, but it’s perfectly reasonable to satisfy both “don’t make me bring oil to the grease monkeys” and “express oil as an explicit dependency of…

Go even has a mantra for this: “accept interfaces, return concrete types”. In the example, I would think to design it such that Oil is just an interface with adapters for either user specified oilType or oilInventory or whatever.

That seems like a more specific version of Postel’s law/the robustness principle:

“be conservative in what you do, be liberal in what you accept from others"

https://en.m.wikipedia.org/wiki/Robustness_principle

Re: Designing Good Interfaces

#20
A good interface is one that allows the user to accurately assess the tradeoffs involved in using this program over some other solution.

In this vein any interface that requires you instantiate all kinds of library-specific structs just to call the relevant function, and conversely upon return, is hiding the actual surface area of the interaction boundary. This makes the aforementioned asessment harder.

This can of course be a justified tradeoff for intended use cases, and this is brings me to my point: An interface author must conscientiously and deliberately adapt the interface to intended use cases.

The user, on the other hand, cannot peer into the mind of the interface author and must measure the analogous intent and purpose of a given interface in the context of his particular requirements.

A good interface, then, is one which the author has designed and documented so that prospective users

(1) accurately determine its suitability to their specific use case,

and (2) are not suprised if and when they decide to make use of it.

Changing the intended use case by exposing or hiding configurability, inverting control or establishing «sane» defaults is a red herring. It has no bearing on the goodness of the interface. Goodness comes from wether configurabiliy, inversion or defaults are apparent to the user.

Edit: spelling/phrasing

Post reply on HN