Slide 1

Slide 1 text

A presentation by @stuherbert
 for @GanbaroDigital Multi-Variance API Versioning For Software Libraries

Slide 2

Slide 2 text

Industry veteran: architect, engineer, leader, manager, mentor F/OSS contributor since 1994 Talking and writing about PHP since 2004 Chief Software Archaeologist Building Quality @GanbaroDigital About Stuart

Slide 3

Slide 3 text

Follow me I do tweet a lot about non-tech stuff though :) @stuherbert

Slide 4

Slide 4 text

@GanbaroDigital ?? ?? Do you create and publish Composer packages?

Slide 5

Slide 5 text

@GanbaroDigital ?? ?? What versioning scheme do you use?

Slide 6

Slide 6 text

@GanbaroDigital ?? ?? Have you ever put out a new version of your package with substantial b/c breaks?

Slide 7

Slide 7 text

@GanbaroDigital I'm here to talk about the consequences of b/c breaks in packages.

Slide 8

Slide 8 text

@GanbaroDigital And to share a different approach from my own packages.

Slide 9

Slide 9 text

@GanbaroDigital This is just my own approach. Other approaches exist. I'm here to learn from you too!

Slide 10

Slide 10 text

@GanbaroDigital In This Talk ... 1. Semantic Versioning 2. Modularity 3. Consequences 4. Library Packages 5. Dev Tools

Slide 11

Slide 11 text

@GanbaroDigital Current Practice

Slide 12

Slide 12 text

@GanbaroDigital Semantic Versioning

Slide 13

Slide 13 text

@GanbaroDigital semver.org

Slide 14

Slide 14 text

@GanbaroDigital X.Y.Z versioning scheme

Slide 15

Slide 15 text

@GanbaroDigital X.Y.Z major.minor.patchlevel

Slide 16

Slide 16 text

@GanbaroDigital X.Y.Z major.minor.patchlevel

Slide 17

Slide 17 text

@GanbaroDigital Fix a bug? Increment Z. e.g. 1.1.0 -> 1.1.1

Slide 18

Slide 18 text

@GanbaroDigital X.Y.Z major.minor.patchlevel

Slide 19

Slide 19 text

@GanbaroDigital Add a new feature? Increment Y, reset Z. e.g. 1.1.1 -> 1.2.0

Slide 20

Slide 20 text

@GanbaroDigital X.Y.Z major.minor.patchlevel

Slide 21

Slide 21 text

@GanbaroDigital Add a major feature? Or break backwards-compability? Increment X, reset Y & Z. e.g. 1.2.0 -> 2.0.0

Slide 22

Slide 22 text

@GanbaroDigital semver is a modern take on old-skool versioning.

Slide 23

Slide 23 text

@GanbaroDigital ?? ?? Why semver?

Slide 24

Slide 24 text

@GanbaroDigital The semver rules are a contract between package maintainers and library users.

Slide 25

Slide 25 text

@GanbaroDigital “Library users should be able to upgrade to the latest X.*.* release without changing their code.

Slide 26

Slide 26 text

@GanbaroDigital e.g. 1.0.0 -> 1.59.46 should be a hands-off upgrade.

Slide 27

Slide 27 text

@GanbaroDigital That is a very high bar for package maintainers to meet.

Slide 28

Slide 28 text

@GanbaroDigital Why? Because of backwards-compatibility breaks.

Slide 29

Slide 29 text

@GanbaroDigital ?? ?? What is a backwards-compatibility break?

Slide 30

Slide 30 text

@GanbaroDigital Changing any existing API.

Slide 31

Slide 31 text

@GanbaroDigital Changing the behaviour of any existing API.

Slide 32

Slide 32 text

@GanbaroDigital Fixing a bug.

Slide 33

Slide 33 text

@GanbaroDigital Adding deprecated warnings to any existing API.

Slide 34

Slide 34 text

@GanbaroDigital Changing the package's dependencies.

Slide 35

Slide 35 text

@GanbaroDigital Changing the supported PHP version(s).

Slide 36

Slide 36 text

@GanbaroDigital Breaking b/c has major consequences for library-users.

Slide 37

Slide 37 text

@GanbaroDigital That's why the semver rules require package maintainers to bump the 'X' version number.

Slide 38

Slide 38 text

@GanbaroDigital ?? ?? What's the knock-on effect if you change your package's major version number?

Slide 39

Slide 39 text

@GanbaroDigital Hold that thought. We'll answer that a little later on.

Slide 40

Slide 40 text

@GanbaroDigital Modularity

Slide 41

Slide 41 text

@GanbaroDigital Most mainstream programming languages are not modular.

Slide 42

Slide 42 text

@GanbaroDigital Libraries are loaded into a shared symbol table.

Slide 43

Slide 43 text

@GanbaroDigital Schemes like namespacing still use the shared symbol table.

Slide 44

Slide 44 text

@GanbaroDigital Schemes like 'friends' simply add access controls. They don't partition the shared symbol table.

Slide 45

Slide 45 text

@GanbaroDigital ?? ?? Which mainstream programming language is modular?

Slide 46

Slide 46 text

@GanbaroDigital JavaScript*

Slide 47

Slide 47 text

@GanbaroDigital ?? ?? The reason your node_modules folders are gigabytes in size?

Slide 48

Slide 48 text

@GanbaroDigital npm* supports installing different versions of the same package into the same app.

Slide 49

Slide 49 text

@GanbaroDigital Composer cannot. Because the language isn't modular.

Slide 50

Slide 50 text

@GanbaroDigital This is not a PHP problem. Nearly all mainstream programming languages share this limitation.

Slide 51

Slide 51 text

@GanbaroDigital I'm not here to debate modular vs non-modular.

Slide 52

Slide 52 text

@GanbaroDigital PHP is a non-modular language. It's going to stay that way for the foreseeable future.

Slide 53

Slide 53 text

@GanbaroDigital I want to look at how we work with the cards we've been dealt.

Slide 54

Slide 54 text

@GanbaroDigital Consequences

Slide 55

Slide 55 text

@GanbaroDigital ?? ?? What's the knock-on effect if you change your package's major version number?

Slide 56

Slide 56 text

@GanbaroDigital If you've used popular Composer packages such as Guzzle, or PHPUnit ...

Slide 57

Slide 57 text

@GanbaroDigital ... you'll have seen errors like this: "Can only install one of: guzzlehttp/guzzle[6.1.0, 5.3.0]"

Slide 58

Slide 58 text

@GanbaroDigital “Two different major versions of the same package cannot co-exist inside the same app.

Slide 59

Slide 59 text

@GanbaroDigital The more popular your package, the more likely it is to be pulled into the same app multiple times.

Slide 60

Slide 60 text

@GanbaroDigital ?? ?? As a library-user, how do you solve this?

Slide 61

Slide 61 text

@GanbaroDigital You can't.

Slide 62

Slide 62 text

@GanbaroDigital ?? ?? As a package maintainer, how can you avoid this?

Slide 63

Slide 63 text

@GanbaroDigital Multi-variance

Slide 64

Slide 64 text

@GanbaroDigital Library Packages

Slide 65

Slide 65 text

@GanbaroDigital In any non-modular language, only one version of your package can exist inside any one app.

Slide 66

Slide 66 text

@GanbaroDigital That's our design constraint. We cannot change it. We have to work with it.

Slide 67

Slide 67 text

@GanbaroDigital ?? ?? Do you build web APIs?

Slide 68

Slide 68 text

@GanbaroDigital If you're building a web API, you support multiple versions of your API at the same time.

Slide 69

Slide 69 text

@GanbaroDigital So why not do the same with library APIs?

Slide 70

Slide 70 text

@GanbaroDigital There's nothing stopping you from having multiple versions of your API inside one package.

Slide 71

Slide 71 text

@GanbaroDigital my-package

Slide 72

Slide 72 text

@GanbaroDigital my-package src

Slide 73

Slide 73 text

@GanbaroDigital my-package src/V1

Slide 74

Slide 74 text

@GanbaroDigital my-package src/V1 src/V2

Slide 75

Slide 75 text

@GanbaroDigital "autoload": { "psr-4": { "GanbaroDigital\\TextParser\\V1\\": "src/V1", "GanbaroDigital\\TextParser\\V2\\": "src/V2" } }

Slide 76

Slide 76 text

@GanbaroDigital We can't use semver for our package version numbers. But package managers expect semver-like version numbers.

Slide 77

Slide 77 text

@GanbaroDigital Version numbers change from X.Y.Z to X.datereleaseno

Slide 78

Slide 78 text

@GanbaroDigital e.g. from 1.2.0 to 1.2018082601

Slide 79

Slide 79 text

@GanbaroDigital e.g. from 1.2.0 to 1.2018082601

Slide 80

Slide 80 text

@GanbaroDigital X is the minimum supported API version

Slide 81

Slide 81 text

@GanbaroDigital Bump X when you drop support for an API version.

Slide 82

Slide 82 text

@GanbaroDigital (but be prepared for all the consequences I've already discussed!)

Slide 83

Slide 83 text

@GanbaroDigital the datereleaseno is the year, month, day + how many releases you've made that day

Slide 84

Slide 84 text

@GanbaroDigital e.g. 1.2018082601 1.2018082602 1.2018082801

Slide 85

Slide 85 text

@GanbaroDigital e.g. 1.2018082601 1.2018082602 1.2018082801

Slide 86

Slide 86 text

@GanbaroDigital e.g. 1.2018082601 1.2018082602 1.2018082801

Slide 87

Slide 87 text

@GanbaroDigital ?? ?? Why not X.date.releaseno? e.g. 1.20180826.01?

Slide 88

Slide 88 text

@GanbaroDigital You want the dependency rules to always pull in new releases of X.*.

Slide 89

Slide 89 text

@GanbaroDigital e.g. 1.2018082601 -> 1.2018082602 1.2018082602 -> 1.2018082801

Slide 90

Slide 90 text

@GanbaroDigital With X.date.release, there's a risk of users adding dependency rules that lock them into X.date.* releases!

Slide 91

Slide 91 text

@GanbaroDigital e.g. 1.20180826.01 would they get 1.20180828.01?

Slide 92

Slide 92 text

@GanbaroDigital This approach is what I call multi-variant packages: multiple API versions inside the same package.

Slide 93

Slide 93 text

@GanbaroDigital ?? ?? Does anyone remember how Guzzle solved this?

Slide 94

Slide 94 text

@GanbaroDigital Dev Tools

Slide 95

Slide 95 text

@GanbaroDigital Here, we're talking about tools like PHPUnit. Something you install that provides new CLI commands.

Slide 96

Slide 96 text

@GanbaroDigital ?? ?? What problems do these CLI tools cause w.r.t. package version clashes?

Slide 97

Slide 97 text

@GanbaroDigital They pull in dependencies of their own, which can clash with your app's dependencies. (Or with the dependencies' dependencies!)

Slide 98

Slide 98 text

@GanbaroDigital ?? ?? How would you solve that?

Slide 99

Slide 99 text

@GanbaroDigital Package maintainers: Ship these tools as PHAR files.

Slide 100

Slide 100 text

@GanbaroDigital End-users: download and use the PHAR files.

Slide 101

Slide 101 text

@GanbaroDigital

Slide 102

Slide 102 text

Thank You How Can We Help You? A presentation by @stuherbert
 for @GanbaroDigital