-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
217 lines (181 loc) · 9.28 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="en" />
<title>Samver</title>
<meta name="Description" content="A Semver Alternative" />
<meta name="Keywords" content="samver versioning semver" />
<meta name="why_are_you_awake_right_now?" content="http://www.principiadiscordia.com/bip/5.php" />
</head>
<body>
<h1> Sam's Versioning: Samver </h1>
<h2> Stop Abusing Semver </h2>
<p>
I like semver. I work as a systems folk, and I end up neck deep in other peoples' dependencies more often than I would
like. For libraries, semver is pretty good.
</p>
<p>
That said, I've run into a cult of programmers who see semver as the best thing next to Jesus coming back for solving
all their problems. And they go to alllll the meetings. Some things I've seen:
<ul>
<li> Making an API for an external bank? Put semver in the URL so they can pick their version! </li>
<li> Oh you're on version 1.124.0 huh? That many commits and not a single breaking change. Right. </li>
<li> 0.2.191. In a Jenkins job. </li>
<li> A Helm chart wraps a Docker container which wraps a binary, and two sidecars. They <i>all</i> have different
semvers. Question for the audience: What broke?</li>
<li> Try out Go modules! How many 0.0.0-x-y modules can you find? </li>
<li> Chef Cookbooks. There is no one better than old school SysAdmins for defining programatic interfaces. What better
way to discover a patch bump was a lie than 2000 servers telling you in slack?</li>
<li> 2021.06.24: the mock wheel is at 2.0.0, but the types-mock wheel went from 0.1.1 to 0.1.3. Does mypy pass? </li>
<li> 2021.08.03: terraform kubernetes provider is pinned at `~> 2.3`, an automatic <b> feature </b> upgrade to 2.4 reports incompatibility with terraform 0.12, breaking pipelines. </li>
<li> 2023.10.04: Kubernetes upgrades from 1.15 to 1.16, tens of APIs have subtle changes. Do addons keep working? https://kops.sigs.k8s.io/contributing/addons/#semver-is-not-enough-id </li>
</ul>
<p>
The key idea around semver is around choice. If your users have the ability to actively choose what version of your
software they're using, it works. But large amounts of software is foundational, in that it needs to keep working for a
long time to allow for progress to be made above it. This is common in infrastructure, where we are so low in the stack
the ripple effects of changes end up costing an enormous amount.
</p>
</p>
If your users don't have a choice as to how they consume your software (its behind an API, its a hidden script that produces a
report, etc), <b>dont break your API.</b> Make a new thing, name it something else, figure out the migration that makes
sense for you and your users. And if you learn to communicate major releases within the context of your users, theres
probably a good chance you could use that knowledge to better communicate features and bugfixes than trying to encode
it into a single number that's an incidental string to your package manager.
</p>
<p>
Do your users even care what version of your software they're using? Or do they just want it to work?
</p>
<p>
Another small note, when dealing with automated CI/CD pipelines, the developer must always specify the semver to the
automation. Semver throws a complexity wrench in what would otherwise be straight-forward automated releases. Determining
what changed at an interface level in the best case requires scraping contrived commits or doc files in the repository,
which must be reliably updated by every developer (lol). There is a way to programatically compare an interface and bump
a semver string automatically, but down that path lies Swagger diffing and RAML and "Codeless" startups, and ahhh good luck
with that.
</p>
<h2> An Alternative </h2>
<p>
Are you releasing software to other developers who are making concious choices on when and how to depend on your software,
as part of a dependency tool (like ruby gems) across an organizational boundary? Then maybe use semver. Update your CHANGELOG
and please set some releases in Github so we have a chance to understand which ways up.
</p>
<h4> OTHERWISE </h4>
<p>
You should probably just automatically generate (DERIVE!) the version based on source code for the benefit of everyone involved.
So what would the best way to do that look like?
</p>
<p>
When I'm digging around in whatever new wibblywobbly landed on my desk that day, I'm going to need a vague idea of what
generation of code I'm working on, and most importantly a way to trace that specific species of wibblywobbly through the
various artifact stores (they keep making more of them?) and eventually back to whichever repository it crawled out of.
</p>
<p>
Without outside information, when trying to communicate a feature or a bugfix, whats easier, "/foo was added in version
27" or "/foo was added in 2008.02.28" ?
</p><!–– 23 skidoo ––>
<ul>
<li>
Right, so <b> lets use a date. </b>
</li>
</ul>
<p>
Who's date? The date the customer sees it or the date the developer wrote it? Hopefully you have a continuous deployment
pipeline in place, in which the customer gets an evergreen version without thinking about it, in which case our versioning
should be developer centric.
</p>
<ul>
<li>
So <b> lets use the commit date of the code.</b> (All artifacts are generated from source control right?)
</li>
<li>
But which branch? Oh no. So <b> lets add the commit SHA.</b> But not too long there.
</li>
<li>
<b> Oh and I want it sortable. </b>
</li>
</ul>
So lets use:
<h4> YEARMONTHDAYHOURMINUTE-GITSHA(short), ex: 201909031732-aa314da </h4>
Or in its semver compatible format:
<h4> YEARMONTHDAY.HOURMINUTE.SECOND+GITSHA(short), ex: 20190903.1732.47+aa314da <h4>
<h2> Sorting Samver </h2>
<p>
Use standard unix `sort` in any flavor installed on any machine. Be aware there is no way to correctly sort commits
made in the same second.
</p>
<p>
Meanwhile if you are stuck in semver land, you can use <a href='https://github.com/samrees/semversort'>https://github.com/samrees/semversort</a>.
</p>
<h2> Sample Implementation </h2>
<p>
<pre>
#!/usr/bin/env bash
# -- samver
# -- in a git repo, spits out a goodly version
if date --version &>/dev/null; then
# GNU
echo $(date --utc --date="$(git show -s --format=%ci)" +%Y%m%d%H%M)-$(git rev-parse --short HEAD)
else
# BSD
echo $(date -u -j -f %s $(git show -s --format=%ct) +%Y%m%d%H%M)-$(git rev-parse --short HEAD)
fi
</pre>
</p>
<h2> F.A.Q. </h2>
<p>
<b> What do I do if I commonly have multiple commits in the same minute? </b>
<li>
Add a %S to your date format to get second resolution.
</li>
</p>
<p>
<b> What do I do if I commonly have multiple commits in the same second? </b>
<li>
You are either abusing git or are working on such a large monorepo that you should not be taking advice from a random page on the internet.
</li>
</p>
<p>
<b> What do I do if I have to use something insistent on semver? </b>
<li>
If you have something awful like the helm packager for kubernetes, that FORCES you to use semver, that assumes that every service you build you
should indicate what changed with a single number, even if the helm chart you're deploying is a custom built artifact of tens of services bound
together as a monolith, with hundreds of API endpoints... well I pity us both. You'll see errors like this:
</li>
<li>
<pre>
Error: Error parsing version segment: strconv.ParseInt: parsing "20191025125407": value out of range
</pre>
</li>
<li>
To avoid that, you can fool it by trying a date format like this: +%Y%m%d.%H%M.%S, which prints something about like this: 20191025.1855.47. Or %N instead of %S on linux (not bsd bfytw) for nanoseconds.
You also need to adjust it to be + instead of a - to be "build metadata" (ex 20191025.1855.47+a5a7ec2), otherwise semver treats it as a "pre-release". AND pipe through the minor and patch versions through
something like $((10#${MINOR})) in bash to do a base 10 conversion to ensure they don't have leading zeros (ex: 2019025.0859.01), as that leading zero makes for invalid semvers.
</li>
<li>
<pre>
Error parsing version '20200821.1845.33-0276160': Version segment starts with 0
</pre>
</li>
<li>
This one honestly looks like semver has encoded a type system bug into the spec. So while pre-releases seem like arbitrary strings in all other cases, if they happen to look like a number they cannot have leading zeros.
That means our foolery causes some libraries to toss errors. <a href="https://semver.org/#spec-item-9">https://semver.org/#spec-item-9</a> This can be fixed by replacing leading zeros with a letter: sed -E '/0[0-9]+$/s/^0/z/'
</li>
</p>
<p>
<b> Should I rethink the semantic overloading of strings in other contexts, like filenames? </b>
<li>
Yes. Please. We can build better interfaces than this madness of contortionism, stuffing our lives and systems into strings. Store the tiniest pointer you
can back to some sort of real database, even if its just a UUID pointed to a JSON in whatever key value store that looks handy. You will not get the interface
correct the first time, I know, I've tried, many times. Updating the "db" is easier than updating the elements out in the wild, every time.
</li>
</p>
<pre>
--
Sam Rees, Computer Plumber
Chicago
</pre>
</body>
</html>