by Darmani on 9/30/22, 9:50 AM with 13 comments
by jvanderbot on 10/1/22, 3:58 AM
"If a depends on b, but falls back to c if b isn't available, does a really depend on b?"
Come on, we're not context-free parsers. Ambiguity and subtlety may be an annoying part of communication but they aren't all that important to focus on like this.
by YeBanKo on 10/1/22, 3:59 AM
by csours on 10/1/22, 4:18 AM
But when you pretend this way, you make many assumptions. It is good to have a shared vocabulary for these assumptions.
by AtlasBarfed on 10/1/22, 6:05 AM
https://en.wikipedia.org/wiki/Liskov_substitution_principle
1) Framework: if your scheduler logic is liskov substitutable with another scheduler, yes, you don't depend on the tasks
2) Shared Format: A writes to file, B reads it: again, the file is a transport mechanism that can be abstracted behind a Liskov substitutable interface. Serialization/Marshalling can abstract the format
3) Modifying a global variable? What a dumb question.
4) Crash puzzles: exception walls solve these as do standard error codes/exceptions in the liskov interface.
5) These are solved by liskov by interfacing with impls that have fallback. Or, read a book on a hundred and one patterns to solve it.
6) errors are part of interfaces. dumb example
7) cycled dependencies, again, don't matter if there are Liskov boundaries. Who cares what the impls are using if the Liskov boundaries are respected and defined. Exception: see next paragraph
The only thing this is significant for is when two incompatible versions of the same library pollute the imports/classpath/whatever. THAT is a problem when dealing with lots of library imports and their downstream/transitive imports/dependencies, regardless of language in mature programming situations. But... there's a reason that's called "a dependency", so those are ... dependencies.
Of course that really isn't listed.
by layer8 on 10/1/22, 9:43 PM
The article in its final definition of “dependence” talks about causation, but logical deduction (proof steps) seem more fundamental to me. It also talks about permissible changes, but the assumption that only permissible changes are talking place is just that, an assumption about the dependency.
by Niksko on 10/1/22, 7:44 AM
by danielnicholas on 10/2/22, 2:55 PM
- In safety- or security-critical systems, you may want to define a small trusted base, or to be able to audit the system to be confident that certain failures won’t occur (https://groups.csail.mit.edu/sdg/pubs/2009/dnj-cacm-4-09.pdf). Reasoning about such things requires being able to say when one part depends on another. Existing definitions of dependency are too vague or incomplete to support such reasoning, let alone to build tools.
- The puzzles are our attempt to distill issues that arise in practice to the simplest possible examples, so if they sound obvious, so much the better. The fallback case is important in critical systems. Suppose you build a component X and you’ve reasoned that it meets a spec S required by a client C. But then you’re not completely confident in your reasoning, so you build a simpler fallback version X’ that you switch to if X fails to meet some property at runtime. Presumably when you reason about C you’ll want to account for X’ as well. This is a basic engineering issue and not a linguistic nicety.
- The problem is to account for systems the way they’re actually built, not to propose a new way to build them. Even if your code was built with objects, the Liskov Substitution Principle wouldn’t be enough because it only addresses subtyping. Global variables, for example, can’t be ignored. They were pervasive in the car code that JPL analyzed as part of a study I was involved in (https://nap.nationalacademies.org/catalog/13342/trb-special-...), and they arise implicitly in OO code whenever you have static features. Another example: if you’re designing a Mars rover, you’d want to account for failures in a battery maintenance module even for modules that make no calls to it. Interfaces can’t account for this kind of thing.
- @layer8 offers a nice formulation of dependence in terms of reasoning and properties. This was a starting point for our work, and I’d previously suggested a model like this in a 2002 paper (https://groups.csail.mit.edu/sdg/pubs/2002/monterey.pdf) and Eunsuk Kang and I suggested a diagrammatic notation for it in a later paper (https://eskang.github.io/assets/papers/mj_workshop_09.pdf). One key limitation of this approach is (as @csours notes) that it doesn’t let you account explicitly for all the assumptions you typically make in such reasoning. It’s not clear, for example, how such an approach could account for Log4Shell.
- A historical note: I first learned about making dependences explicit from Barbara Liskov and John Guttag from TAing their class (https://mitpress.mit.edu/9780262121125/abstraction-and-speci...). Even back then, we realized that the dependence model was only an approximation, and that it couldn’t be derived from the code. Long after Barbara developed her substitution principle, when we taught the same class together (in 1997) we continued to use dependence diagrams, because they address a different problem.