HackerTube 中文?
Software boundaries and change →

What does a module promise its callers?

Try replacing a module whose callers rely on its incidental return order. Start with what the interface says, then trace the decisions it hides and the behaviors people have learned to expect.

Questions in this reading · 13
  1. Which choices should an API leave out?
  2. How much can a small interface hide?
  3. Small objects or small interfaces?
  4. When does a module boundary freeze a decision?
  5. When does an implementation detail become a promise?
  6. When does an implementation detail become a promise?
  7. Can two versions coexist under the same name?
  8. Which operations is the caller buying?
  9. Does a valid signature settle which history to keep?
  10. Where did the hidden cost go?
  11. Is starting the old program enough for compatibility?
  12. Who migrates when a field becomes mandatory?
  13. How long must “it heats” hold to count as delivery?

Which choices should an API leave out?

Removing an uncertain feature reduces what clients must learn. Separating tangled concerns reduces how many choices they must consider together.

Compare original passages and timestamps · 2
When it doubt, leave it out.
How To Design A Good API and Why it Matters · ▶ 24:42–24:45
start seeing interconnections between things that could be independent
"Simple Made Easy" - Rich Hickey (2011) · ▶ 59:28–59:32

How much can a small interface hide?

A small API reduces the concepts callers must learn. A deep module makes that small surface useful by hiding substantial implementation behind it.

Compare original passages and timestamps · 2
When it doubt, leave it out.
How To Design A Good API and Why it Matters · ▶ 24:42–24:45
very simple interface with a very large amount of functionality underneath it
A Philosophy of Software Design | John Ousterhout | Talks at Google · ▶ 14:24–14:29

Small objects or small interfaces?

One talk breaks code into smaller responsibilities. The other limits what callers must learn. Count the decisions exposed to callers as well as the objects inside the implementation.

Compare original passages and timestamps · 2
make smaller things
RailsConf 2014 - All the Little Things by Sandi Metz · ▶ 0:54–0:58
When it doubt, leave it out.
How To Design A Good API and Why it Matters · ▶ 24:42–24:45

When does a module boundary freeze a decision?

An interface can shelter callers from a changing implementation. Once clients depend on its behavior, changing the interface itself becomes more expensive.

Compare original passages and timestamps · 2
the higher the cost of communication the less iteration will happen there
The Only Unbreakable Law · ▶ 27:06–27:16
not be able to take it out once you put it into an API.
How To Design A Good API and Why it Matters · ▶ 24:57–25:03

When does an implementation detail become a promise?

Callers can depend on observable behavior that was never documented. Changing an interpreter or a library then becomes a compatibility decision.

Compare original passages and timestamps · 2
people actually depend in very bizarre ways on some of the internals
How Python was Shaped by leaky Internals, Armin Ronacher, Flask framework · ▶ 4:31–4:38
anything a user can observe about the implementation of your API
CppCon 2017: Matt Kulukundis “Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step” · ▶ 5:19–5:27

When does an implementation detail become a promise?

Interpreter behavior, hash tables and public APIs illustrate how callers come to rely on what they can observe. Observable behavior need not have been formally guaranteed.

Compare original passages and timestamps · 3
people actually depend in very bizarre ways on some of the internals
How Python was Shaped by leaky Internals, Armin Ronacher, Flask framework · ▶ 4:31–4:38
they will rely upon it, given enough users.
CppCon 2017: Matt Kulukundis “Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step” · ▶ 5:27–5:32
not be able to take it out once you put it into an API.
How To Design A Good API and Why it Matters · ▶ 24:57–25:03

Can two versions coexist under the same name?

A module name can force a choice between versions. Identifying content by its hash gives each version a separate address.

Compare original passages and timestamps · 2
we would have to make S modules also have a version identifier
How Python was Shaped by leaky Internals, Armin Ronacher, Flask framework · ▶ 39:11–39:16
then it would be perfectly fine to allow as many different versions of the same library in our code base
"Unison: a new distributed programming language" by Paul Chiusano · ▶ 26:04–26:16

Which operations is the caller buying?

A caller using a square root can leave the improvement of successive guesses inside the procedure. A tree interface promising constant-time parent lookup makes a second commitment. The succinct-structures lecture encodes the tree as bits and relies on rank and select for navigation. Write down separately what the operation returns, how much time it may take, and how much extra index space that time requires. Replacing the representation can preserve one promise while breaking another.

Passages and timestamps · 3
using black-box abstraction to suppress detail.
Lecture 1A: Overview and Introduction to Lisp · ▶ 13:03–13:07
If I have rank and select in constant time, now I can do left child, right child, parent in constant time.
17. Succinct Structures I · ▶ 32:35–32:41
all I'm allowed for rank and select is little o of n space.
17. Succinct Structures I · ▶ 33:34–33:39

Does a valid signature settle which history to keep?

Send one payment to two nodes. Each can check the signature, but if two individually valid histories conflict, the signature does not choose between them. Gensler asks who appends the next block; the Bitcoin walkthrough introduces cumulative work as part of the rule for choosing a valid history. The 256-bit calculation instead estimates generic trials to hit a particular hash target. That measures one computational task. It cannot certify the separate rules for authorizing messages, validating ledger entries and selecting a history.

Passages and timestamps · 3
how do you decide who appends that next block?
1. Introduction for 15.S12 Blockchain and Money, Fall 2018 · ▶ 18:33–18:39
the one with the most work put into it
But how does bitcoin actually work? · ▶ 19:10–19:22
on average, 2 to the 256 guesses
How secure is 256 bit security? · ▶ 0:33–0:37

Where did the hidden cost go?

One hash lookup may probe a dense run of entries; another may chase pointers to distant addresses. Carruth’s data-structures talk follows the actual accesses. Carry that question into his talk on abstractions: tidy instructions at one call site can coexist with compilation costs or a calling-convention penalty at another boundary. A performance promise needs a workload, a boundary and an account of who pays.

Passages and timestamps · 2
maximize the cache locality of of handling a collision
CppCon 2014: Chandler Carruth "Efficiency with Algorithms, Performance with Data Structures" · ▶ 49:33–49:43
it just means the cost is paid somewhere else
CppCon 2019: Chandler Carruth “There Are No Zero-cost Abstractions” · ▶ 16:44–16:51

Is starting the old program enough for compatibility?

Rename a field in a message and the producing service may still compile. Hickey points out that names crossing a process boundary have other readers. Goetz distinguishes linking an old binary, recompiling old source and preserving behavior at runtime. Keep an old artifact, old source and an old message, then exercise them separately. Each tests a different promise.

Passages and timestamps · 2
as your names start escaping out of your processes, that they are global names
The Language of the System - Rich Hickey · ▶ 21:29–24:03 · passage interval
existing class files will continue to link
Brian Goetz - Stewardship: the Sobering Parts · ▶ 20:53–20:59

Who migrates when a field becomes mandatory?

In Hickey’s terms, a mandatory field raises the caller’s obligations. Winters’s diamond dependencies explain why two teams may not move together: each reaches a shared component through a different intermediary. Wright supplies a migration order: offer the replacement while retaining the old default, move callers in batches, then end the transition. A version number can identify the two interfaces but cannot supply the missing data for an unmigrated caller.

Passages and timestamps · 3
if you require more than somebody who's giving less now is not going to get what they want
Spec-ulation Keynote - Rich Hickey · ▶ 24:55–25:05
If everyone in your infrastructure doesn't upgrade at the same time, then we have version skew.
CppCon 2017: Titus Winters “C++ as a "Live at Head" Language” · ▶ 15:30–15:36
Usually you add the new thing without making it the default.
CppCon 2018:H. Wright “Large-Scale Changes at Google: Lessons Learned From 5 Yrs of Mass Migrations” · ▶ 13:15–13:19

How long must “it heats” hold to count as delivery?

Thwaites counts hundreds of pieces in a cheap toaster. His own device heats briefly before its element melts. As interface promises, “produces heat when switched on” and “continues heating for a useful interval” give different verdicts on the same device. To test the latter, include the duration and the state after failure in the acceptance example.

Passages and timestamps · 2
that, inside this object, which I'd bought for just 3.49 pounds, there were 400 different bits made out of a hundred-plus different materials.
Thomas Thwaites: How I built a toaster -- from scratch · ▶ 1:39–1:51
And for about five seconds, the toaster toasted, but then, unfortunately, the element kind of melted itself.
Thomas Thwaites: How I built a toaster -- from scratch · ▶ 10:31–10:40

Try it on your own example

For an interface you plan to change, which behaviors are guaranteed and which have merely stayed the same?