Spec-ulation
Rich Hickey Deconstructs Semantic Versioning
https://www.youtube.com/watch?v=oyLBGkS5ICk
tl;dw
When Rich Hickey speaks, it’s a good idea to listen. He is able to see things that many of the rest of us cannot, and he is able to analyze and explain his thoughts with a precision that is rare even among programmers.
Little did I know that there was a problem with semantic versioning. It seemed like a reasonable system, and I never gave it a second thought until I watched this presentation where Rich exposed what the semantics of this system actually were.
Briefly, the semantics of x.y.z
- z changes - don’t care.
- y changes - don’t care.
- x changes - you’re screwed.
That’s all this system can tell you.
Furthermore, this system implicitly formalizes software breakage by saying if you change x, you’re allowed to make backward incompatible changes.
However, do we have to break our software?
Rich points us toward another way.
0:00 Spec-ulation
Rich Hickey
0:58 This is not a talk about spec
It’s a talk about what spec is about
- Giving something to someone that they can use
- Making a commitment
- i.e. not taking it away later
2:46 Change
is it a thing?
3:35 ‘Change’
Origin:
- from Latin cambire “to exchange, barter”
You could change a cow into wheat!
- c.f. Eurogames
One-sided change is… theft?
- Anti-social at least
Productivity and soul-crushing at worst?
5:13
We want our software (esp. libraries/services to be different/better tomorrow.
What will that mean for our consumers?
5:42 Dependencies
[image of versioned library dependency tree]
6:59 But…
Artifacts don’t actually use other artifacts
There is nothing in the code about artifacts
7:45 Dependencies Redux
[image of versioned library dependency tree broken down by namespace] [exposes opportunity for dead code elimination; don’t need library z]
9:46 But…
Namespaces/packages don’t actually use other namespaces/packages
At least require/import appear in the code
Where is the mapping to artifacts? [no mapping of artifact to namespaces]
10:48 Dependency Truth (code)
[image of namespaces further broken down by function dependencies] [shows hat lib X is not a true dependency]
13:45 Do deps Force Versioning?
“What you can do is let Semantic Versioning provide you with a sane way to release and upgrade packages without having to roll new versions of dependent packages” http://semver.org/spec/v2.0.0.html
Is that what happens?
Often, no, cascading version bumps
to let root ‘know’ about improvements to leaves, even if path nodes’ code unchanged
level violation
15:27 Names, Levels, Scopes, Contexts
fns depend on (call) fns by name
ns/packages requires/includes set up a context in which those calls can succeed
Artifact deps/poms set up a context in which those requires can succeed
fn name scopes include ns but not artifact
- artifact context is MAGIC
17:19 Basis
Why do we put things in our deps?
We need access to libs while developing
Maven chases transitive deps
Incorporated in artifact to communicate needs to our consumers
“we tested against x,y,z”
But, course-grained, implies too much
- doesn’t capture actual deps, just context
19:49 (Ex)changes in Software :important:declarations:
What is required?
fn - args
ns - var names
artifact ns/package names/paths
What is provided?
fn - ret (proc/service effect)
ns - vars/fns
artifact - namespaces/packages
22:11 Growing Your Software
Accretion
- provide more
Relaxation
- require less
Fixation
- bash bugs
24:14 Breaking Your Software
Require more
Provide less
Unrelated stuff under same name
25:55 Change is Not a Thing
It’s one of two things
Growth
Breakage
In the small (fns), spec can help us determine which, prevent breaking specs
As long as we don’t try to do something silly like versioning specs!
27:56 Recognizing Collections
You only ‘change’ a collection by adding/removing members
Adding = growth, removing = breakage
Namespaces - collections of vars/fns
Artifacts - collections of namespaces/packages
Don’t conflate levels!
- My family doesn’t change when I put on a hat
(Everything intersting happens at the leaves.)
29:52 “Semantic” Versioning “Semantics”
1.2.changed
- “you don’t care”
1.changed.0
- “you don’t care”
changed.0.0
- “you’re screwed”
31:18 Even worse…
“you might be screwed”
Considered covering of change at all levels
- Good luck determining where
Might just as well change the name
32:26 Might as well change the name
32:28 MIGHT AS WELL CHANGE THE NAME
32:52 But…
that’s not change, That’s a new thing! Right.
33:09 Which name?
Levels again
33:39 Requiring More args? Providing Less on return?
i.e. incompatible spec
new function
old-ns/foo-2 or new-ns/foo
N.B - the namespace is port of the name
- ns aliases can ease transition
36:14 Providing Fewer fns/vars?
New namespace/package
37:20 Providing Fewer namespaces/packages?
New artifactId?
but… that’s what MAJOR segment is for?
no, “any backwards incompatible changes”
i.e. too-broad “semantic”
The problem is artifact->namespaces magic means possibility of collision
- No ‘scope’ implicitly renaming children
[Rich was not sure what the right strategy for this situaion is.]
40:33 Doesn’t Doing the Right Thing Name-wise Make You Reluctant to Remove Things?
Yes. Good.
41:02 Breaking Changes are Broken
Full Stop
Don’t do it
Don’t try to figure out the best way to do it
Avoid breakage by turning it into accretion
- old and new can co-exist
42:25 So Maven is Broken?
Not really - how we use it may be broken
Maven central doesn’t let you ‘change’ artifacts
and never ‘breaks’, is not versioned!!
- no “I’m using maven central 1234567.0.0”
You’re always hapy to use latest maven central
Why?
it’s an accreting collection of immutable things
44:27 (insert rotten sandwich image here)
46:29 So SemVer is Broken?
Yes
It is, in part, about how to ship breakage
and the other ‘semantics’ are of little utility
What instead?
Maybe chronological versioning?
- YYYYMMDD.HHMMSS
Conveys more and supports some forms of relativism
48:47 What about Git?
Wonderful, immutable, truth-of-the-code system, widely adopted
Content-based addressing
Almost completely ignored by artifacts/versioning, even though code basis
Deserves a role
- but, SHAs vs order/causality/readability
50:37 It’s a Social Thing
We won’t be albe to tech ourselves out of this
We need to agree that treating each other well is important
51:18 Local dev vs Open dev
Incompatible churn acceptable in private
Slack is not standup
OS user base is open and unknown
54:18 Coding for Growth
Open specs and data formats are key
Specs are about what you can do, not about what you can’t
Prohibition turns growth into breakage, cascades
Always presume you might be handed more than what you need or know about
- ignore, or have policy for it
58:31 What about Iterative Development?
Alphas are OK
But maybe should be in artifactId
Or - incremental API ‘publishing’
Open source is not an excuse for indefinite public thrashing around
1:00:14 The Only Truth is Runtime
Deps/POMs are just suggestions
- can be full of ‘conflicts’
Someone needs to build a classpath
- that alone determines runtime context
Possibly a lib set that none of the components have ever run against
1:01:59 Testing is Runtime Dependent
And runtimes are independent (if related) of dev- and build-time deps
Plus, you can’t test against an open set of consumers
Artifact release testing is inherently limited
We could be reifying artifact sets at a macro (e.g. app or multi-app) level
1:03:47 (Live Coding Demo)
1:04:00 What about Web Services?
Same problems, same mistakes
‘versioning’ non-answer
conflating collections w/contents
Web service is collection of ops
ops require/provide
Accretion could prevent a lot of client/service version hell
1:07:04 We Need to Bring FP to the Library Ecosystem
Currently update-in-place, excused but not corrected by versioning
- dependency hell == mutability hell
Makes programming fragile
Libraries less useful
- Even undesirable, whatever their features
1:08:19 “This is Impossible/Impractical”
Nope
Many examples of decade+ compatibility
Unix APIs
Java
HTML
Clojure?
Compatibility a prerequisite of success?
1:09:47 What If We Never Broke Anything?
names become enduringly meaningful
orthogonal compatibility checking becomes possible
find-grained deps can be explored
use the latest with impunity
compose with impunity
1:10:54 Open Challenges
We can’t ‘see’ some changes
collection adds are easy
fn args/ret not visible in source
- specs can help
spec compatibility context-dependent
- provide vs require
repo->artifact->namespaces not first class
tooling that reinforces the status quo
1:12:40 Opportunities for Clojure
spec
Flexible (vs fragile/brittle) dep awareness
Explicit code->artifact/repo support
First-class, fine-grained ‘publish’ for APIs
- ditto deprecation
Testing based on fine-grained deps
- generative testing needs this
1:14:23 Exchange > Change
Grow your software
Give birth to variation
- Don’t break, accrete
Share this post
Twitter
Google+
Facebook
Reddit
LinkedIn
StumbleUpon
Email