Fork me on GitHub
#off-topic
<
2020-06-26
>
p-himik10:06:34

So far, I've been maintaining my changelogs as regular Markdown files. A regular list of versions where each version is accompanied by a list of additions, changes, fixes, etc. But it makes it hard to display such changelogs via web UI in a nice way without dancing around the MD format. I started to think about maintaining a changelog in an EDN file. Or some other format that's not free-form. Then, generating a web UI for it (or even an MD file if someone would need it for some reason) would be trivial. Does anyone have any thoughts on this?

👀 3
vemv11:06:48

curious, web UI -> custom webapp?

p-himik11:06:02

Not sure what "custom webapp" means. In the context of the changelog question, it can be thought of as just "a website".

p-himik11:06:52

To be more concrete - I can generate Hiccup based on some EDN. It's much harder to do that for a Markdown file.

vemv11:06:15

I'm essentially asking if this is simply to be rendered in Github/Gitlab/... or if there's a more sophisticated need

p-himik11:06:10

I need to end up with Hiccup. :) The platform is of no importance.

p-himik11:06:36

And I need to control the way the Hiccup is created. I.e. I will write the code myself.

vemv11:06:14

:thumbsup: ! edn->hiccup seems easy enough git->edn is the hard part, right? You may find some inspiration in https://www.conventionalcommits.org/en/v1.0.0/

p-himik11:06:25

Nah-nah, I don't care about Git. I write my changelogs by hand.

avi12:06:18

> But it makes it hard to display such changelogs via web UI in a nice way without dancing around the MD format. Can you elaborate on this? I’m a huge proponent of maintaining documentation as data — it’s massively useful to decouple content from presentation — but it’s always good to understand the problems thoroughly before discussing solutions. (I don’t mean to imply that you don’t understand the problems thoroughly, rather that I don’t.) The reason I’m asking is because I think of Markdown as a shorthand for HTML. So you’re essentially writing HTML now. Writing HTML directly should provide plenty of flexibility in displaying the information in a nice way. I might be misunderstanding, but it seems to me that generating Hiccup in order to generate HTML does not, in the end, give you any advantage in terms of “niceness” because you end up right back where you started: HTML. Of course, I know that Markdown isn’t HTML; it’s a limited subset. In particular, I’ve found Markdown to be poor for tables. Over the past few years I’ve found myself falling back to “plain old HTML” for representing tables in Markdown documents. This ability is one of the things I like about Markdown; it doesn’t pretend to be fully sufficient for everything, and its definition is very clear that it’s correct to use regular HTML tags in a Markdown document. So you might want to try using HTML for a table in your document? Here’s an example of a changelog that I maintain that uses exactly that technique: https://github.com/FundingCircle/fc4-framework/blob/main/docs/change-history.md Ah, sorry, that’s a Markdown table… I’ll dig up an actual example! Found one: https://github.com/FundingCircle/fc4-framework/blob/c0a9777d3bb908651a0fd4f3dd151277fa10ff93/docs/docs/manual/toolset.md

👏 3
borkdude13:06:11

@U088NU894 You might also have an idea about this since you wanted to write your website exclusively in EDN, not markdown

dominicm14:06:45

I've done things where I've treated asciidoc as an annotated document and extracted data from it. You can get a tree from a document if you need. But you can also just control how elements are rendered.

mmz15:06:54

Not sure if it helps, but I'm experimenting building a website from pure clojure. Only dependency so far: babashka! No configs, no build tools, no frameworks or libraries, no conventions ... no magic. Only clojure and functions. Warning: very early stage, very spartan, but maybe it helps :man-shrugging::skin-tone-3: https://github.com/mmzsource/mxmmz /cc @U04V15CAJ

borkdude15:06:26

@U088NU894 Maybe add a link to where its hosted in the README?

mmz15:06:34

@U04V15CAJ done (but it's embarrasingly little at the moment ... and I actually still have to link it up with my personal domainname ... you know, the CNAME stuff)

borkdude15:06:57

I can look through the vanilla HTML and can see the potential 🙂

🤓 3
p-himik16:06:55

Thank you all for the input! @U69US348Z There are two main issues with Markdown any any attempts to derive HTML directly from it: 1. It gives you too much freedom that I don't need in mere changelogs - it would be incredibly easy to accidentally break something visually 2. It's not sufficient when you need to get a specific HTML from it. E.g. I need to generate a set of tabs from a changelog that, upon clicking, switch the contents of a separate panel to the changes make in the relevant version. I can imagine that now it's possible to do that with HTML5+CSS3, but either way - I'd rather stick to Hiccup simply because the rest of the website uses it.

plexus06:06:41

FWIW we went the other way, sticking to a fairly rigid markdown format and parsing that. The structure of the markdown for new releases is managed by the release script so there's not too much to screw up. https://github.com/lambdaisland/janus

plexus06:06:15

That's how we create this overview of releases based on the CHANGELOG from all our different projects https://github.com/lambdaisland/open-source/blob/master/RELEASES.md

p-himik06:06:25

Thanks! But I still prefer writing my changelogs/release files by hand, particularly because of entries like "Sort namespaces by name and vars by line number". :) IMO they should not be there at all.

plexus07:06:19

The entries are written by hand 🙂 only the headers are done by the tooling

p-himik07:06:05

Ah, I see, I misunderstood then. So it seems like what I have now is what you have as well, but with less tooling. And I would like to need even less tooling. :) I think with time I have developed a slight aversion to the proliferation of moving parts.

avi14:06:24

@U2FRKM4TW following up: > @U69US348Z There are two main issues with Markdown any any attempts to derive HTML directly from it: That all makes sense! Thanks for explaining. It’s satisfying when these sorts of discussions don’t just peter out, but rather yield a fuller understanding for everyone. It gives us a clear, informative glimpse into others’ priorities, instincts, experience, wisdom, etc. (BTW as I mentioned upthread, I’m a staunch proponent of data-oriented-documentation, in fact I’ve been working on a tool I’m tentatively calling https://github.com/FundingCircle/DaD — for Docs as Data. It has no docs on how it works yet, or even on what it really does, but I suspect you could figure it out by browsing the three dirs in its https://github.com/FundingCircle/dad/tree/main/doc dir. If you have a chance to take a look I’d love to hear what you think; please DM me! But if you don’t have time/interest, no worries, I understand.)

👍 3
plexus14:06:50

That all makes sense. I'm quite happy with out approach now that it's all humming along. But it really pays off because we have a dozen projects that all use the same format and tooling. Standardization can help here. There's https://keepachangelog.com , which is a fairly widely used format, and for which you'll find off-the-shelf tooling. Our format is a variant of keepachangelog's that made more sense to me at the time. Adopting such a format also has the benefit that others can easily consume your changelog, e.g. these bots that make pull requests to update dependencies will often parse changelog files to provide some context about the upgrade. It's also not that much work to automate as part of a release process. Our "tooling" initially was just a bunch of shell+ed scripts to make sure I could very quickly create new releases of Kaocha, basically just bin/release which would create the git tag, update the pom, build the jar, release the jar, update the changelog, trigger a cljdoc build, etc. Now it's all moved to babashka and used across most of our projects.

p-himik14:06:01

> Standardization can help here. There's https://keepachangelog.com , which is a fairly widely used format, and for which you'll find off-the-shelf tooling Absolutely agree, and keepachangelog was exactly the thing that made me write my changelogs manually.

tianshu13:06:19

how to make the wide let expression prettier? when using destructing, it's very easy to have a 100+ columns' width for a line.

borkdude13:06:05

use newlines? can you give an example of a destructuring for of 100+ columns wide?

tianshu14:06:35

some code like this

(defn create-message
  [params]
  (let [{:keys [sender text token emails names group-id image-url] :as params}
        (s/conform :rtm/create-message params)

        {sender-uid :id :as sender-user}
        (impl/try-get-user-by-sender {:sender sender :token token})

        receiver-vchannel-ids
        (impl/collect-receiver-vchannel-ids sender-uid {:group-id group-id :emails emails :names names})

        [with-file? {:keys [file-mime file-name file-base64] :as file-params} :as file-conform]
        (s/conform :rtm/create-with-file? params)

        [with-tags? {:keys [tags] :as tags-params} :as tags-conform]
        (s/conform :rtm/create-with-tags? params)

        ;; Initialize processing context
        context {:params params
                 :config/file-size-limit *file-size-limit*}]

    ;; Interrupt for bad params
    (when (s/invalid? file-conform) (err/rtm-invalid-file-params))
    (when (s/invalid? tags-conform) (err/rtm-invalid-tags-params))

    ;; Processing
    (cond-> context
      (= with-file? :with)
      (impl/process-message-file! file-params)

      (= with-tags? :with)
      (impl/process-message-tags! tags-params)

      (u/external-url? image-url)
      (impl/process-message-external-image! image-url))))

tianshu14:06:04

I just make it use newline

tianshu14:06:50

Oh, I mean 100 columns, not 100 keys:joy:

borkdude14:06:45

@doglooksgood yeah, so use new-lines, I don't see the problem?

tianshu14:06:33

Personally don't like so many blank lines. If this function is shorter, it's a bit weird to have some blanks inside.

vemv14:06:57

blankline != newline personally I tend to add them after hashmap kv pairs, so that my editor can align the hashmap vertically:

(defn create-message [params]
  (let [{:keys [sender text token emails names group-id image-url]
         :as   params}
        (s/conform :rtm/create-message params)
        {sender-uid :id :as sender-user}
        (impl/try-get-user-by-sender {:sender sender :token token})
        receiver-vchannel-ids
        (impl/collect-receiver-vchannel-ids sender-uid {:group-id group-id
                                                        :emails   emails
                                                        :names    names})
        [with-file? {:keys [file-mime file-name file-base64]
                     :as   file-params} :as file-conform]
        (s/conform :rtm/create-with-file? params)
        [with-tags? {:keys [tags]
                     :as   tags-params} :as tags-conform]
        (s/conform :rtm/create-with-tags? params)
        ;; Initialize processing context
        context {:params                 params
                 :config/file-size-limit *file-size-limit*}]
    ))

borkdude14:06:07

blank lines? I thought your problem was with line length...

borkdude14:06:54

right, what @vemv is showing, is what I meant

tianshu14:06:48

but in this case, it's hard to recognize, for example, is receiver-vchannel-ids for left or right?

👍 6
borkdude14:06:25

that's a trade-off. either you have short lines or better readability

borkdude14:06:01

Linus Torvalds recently wrote about this in an e-mail..

tianshu14:06:17

for what? about line length?

tianshu14:06:48

I can understand the 80 length is made for old terminals, for the code I paste, if write pair in a single line, there is another problem, that is you don't know where to split the pair

vemv14:06:04

I've used the generous but real limit of 130 columns for a few years now. I chose it after github's limit (128) before it triggers horizontal scrolling With 130 I very very rarely have to reshape let bindings unnaturally So, might be a middle ground :)

tianshu14:06:26

this could be affected by font size?

👍 3
tianshu14:06:18

(defn create-message
  [params]
  (let [{:keys [sender text token emails names group-id image-url] :as params} (s/conform :rtm/create-message params)
        {sender-uid :id :as sender-user} (impl/try-get-user-by-sender {:sender sender :token token})
        receiver-vchannel-ids (impl/collect-receiver-vchannel-ids sender-uid {:group-id group-id :emails emails :names names})
        [with-file? {:keys [file-mime file-name file-base64] :as file-params} :as file-conform] (s/conform :rtm/create-with-file? params)
        [with-tags? {:keys [tags] :as tags-params} :as tags-conform] (s/conform :rtm/create-with-tags? params)
        context {:params params :config/file-size-limit *file-size-limit*}]
    ...))
And code like this, I can hardly split pairs. there's no = or <-

vemv14:06:45

(defn create-message
  [params]
  (let [{:keys [sender text token emails names group-id image-url]
         :as params} (s/conform :rtm/create-message params)
        {sender-uid :id
         :as sender-user} (impl/try-get-user-by-sender {:sender sender
                                                        :token token})
        receiver-vchannel-ids (impl/collect-receiver-vchannel-ids sender-uid {:group-id group-id
                                                                              :emails emails
                                                                              :names names})
        [with-file? {:keys [file-mime file-name file-base64]
                     :as file-params} :as file-conform] (s/conform :rtm/create-with-file? params)
        [with-tags? {:keys [tags]
                     :as tags-params} :as tags-conform] (s/conform :rtm/create-with-tags? params)
        context {:params params
                 :config/file-size-limit *file-size-limit*}]
    ))
* Under 100 cols * No blank lines * Each binding is in the same given line

tianshu14:06:45

I think this is not a good idea, when the right side becomes longer.

tianshu14:06:12

okay, I should just accept the newline + blank line

vemv14:06:10

yeah nothing set in stone :) one can mix and match different styles, depending on the code at hand

👍 3
tianshu14:06:22

unless align it with C-c SPC, but that would be really wide..

deactivateduser17:06:30

Riffing off of https://clojurians.slack.com/archives/C6QH853H8/p1593191210025400 (a short thread about semantic versioning)…

deactivateduser18:06:08

(please read that entire, short thread before joining in here, or else what I say next won’t make sense 😉)

deactivateduser18:06:05

So my last question (better answered here) was “So criticism is great, but what’s the alternative?”

dvingo18:06:22

regarding alternatives to semver: how about never introduce breaking changes - always accrete or introduce new names via different namespaces? For actual version syntax I'm liking ISO 8601 date-based versions as it actually provides some semantic value - when the code was published, and they sort as you'd expect when treated as strings, incremental versions within the same day work by adding an integer sequence "2020-06-26" <- first version, "2020-06-26-1" <- 2nd, "2020-06-26-2" <- 3rd

deactivateduser18:06:35

Having lived through the “wild west” of C, C++ and then pre-Maven Java versioning, I have no desire to return to that disaster area.

deactivateduser18:06:42

@danvingo absolutely something worth aspiring too. But also (sadly) not always possible, and when backwards compatibility is broken (however “broken” is defined - a separate and complex topic in and of itself…) I think it’s valuable to a) communicate that in a crystal clear fashion to downstream, and b) give downstream the option to stay on the current version until such time as they can absorb the cost of upgrading and fixing the fallout from the breaking change(s).

phronmophobic18:06:22

never introducing breaking changes isn't really possible unless you you never introduce changes. obviously, there are degrees and avoiding breaking other people's code is a very valuable thing. it's one of the reason I like the clojure ecosystem generally

☝️ 3
phronmophobic18:06:37

it seems (to me) that the crux of the debate is what information, if any, a "version" should communicate

💯 3
phronmophobic18:06:29

some people think that any changes are best communicated outside of a version string (any unique identifier will do) and some people think that it's useful to have your version string communicate more (eg. size of change, time of change, etc)

phronmophobic18:06:27

this is pretty cool

deactivateduser18:06:38

How do the authors of core.async decide when to increment MAJOR vs MINOR? That page gives no indication, which doesn’t give me (as downstream) anything to base my upgrade decisions on.

phronmophobic18:06:25

I think the point is that the difference between MAJOR and MINOR is subjective since it depends on the consumer of the library. you have the same problem with semver. it tries to delineate between backwards compatible changes non backwards compatible changes. however, whether a change is backwards compatible depends on the consumer of the library.

borkdude18:06:05

The only importantant bit is "never breaks" so upgrading is always safe, at your option

deactivateduser18:06:11

At least SemVer (whether we agree with their definition or not) attempts to provide some standardisation around increments.

borkdude18:06:23

Just read the release notes I guess

deactivateduser18:06:19

Right, and “never breaks” would, in a SemVer world, mean that your package would have 1.MINOR.COMMITS versions “forever”, which is absolutely acceptable (and I would say even encouraged) by SemVer.

deactivateduser18:06:16

But… …if, heaven forbid, reality gets in the way of one’s carefully laid plans and one finds that a breaking change is unavoidable, SemVer gives you an “out” - roll out a 2.0.COMMITS version.

deactivateduser18:06:53

I mean I assume that’s why in more than a decade Clojure is still at 1.x.y (which, btw, I’m a huge fan of).

hiredman18:06:11

the thing with semantic versioning though is the decision of which number to bump is very subjective

borkdude18:06:15

The Clojure way would be to introduce a new name(space)

borkdude18:06:24

and this is always possible

borkdude18:06:50

and if that's really really not possible, it will just be a new lib

hiredman18:06:05

and if your software is always 1.minor.commits, why not just drop the 1?

phronmophobic18:06:25

I think the point is that the difference between MAJOR and MINOR is subjective since it depends on the consumer of the library. you have the same problem with semver. it tries to delineate between backwards compatible changes non backwards compatible changes. however, whether a change is backwards compatible depends on the consumer of the library.

deactivateduser18:06:54

Absolutely, hence why above I deliberately wrote “however “broken” is defined - a separate and complex topic in and of itself…“.

deactivateduser18:06:47

That, to me, is the fundamental crux of this question - how does one define “breakage”. The question of whether and/or how to use a version label to try to succinctly communicate that is really just a derivative of that fundamental question.

deactivateduser18:06:50

But I would assert that if you decide to use version labels to try to distill that information, SemVer is a good way to do it.

deactivateduser18:06:11

(without stating an opinion either way as to whether version labels are the “best” way to communicate breakage)

slipset18:06:40

Seems like we are discussing two things here. One is what kind of versioning scheme should one use if one doesn’t use sem-ver (which includes the topic “what does 1.x.x mean when not using semver, eg core.async) and the other is how to maintain something without introducing breaking changes.

slipset18:06:24

And of course a third thing, which is what is a breaking change.

slipset18:06:42

I think Rich did a fairly good job of defining breakage in his talk. What I was missing is how to deal with this in my day to day life as a lib maintainer. I guess @seancorfield showed us how when he created jdbc.next instead of adding new namespaces to java.jdbc.

slipset18:06:54

So I imagine that java.jdbc will only see “fixation” kind of changes, but no others.

seancorfield18:06:32

When I started with next.jdbc, my guiding principle was that 1.0.0 would be the first stable release and I would (try to) never break anything after that. So there were months of alpha and beta releases before 1.0.0 and after a handful of 1.0.x releases I decided to go to 1.0.COMMITS to match the Contrib library moves -- and I've switched most of my libraries over to 1.0.COMMITS now.

seancorfield18:06:51

Only the Alpha builds had breaking changes: https://github.com/seancorfield/next-jdbc/blob/develop/CHANGELOG.md#alpha-builds -- I changed to Beta only when I made my last breaking change (renaming reducible! to plan). I am fairly certain there have been no breaking changes since then, just additions and some bug fixes.

seancorfield18:06:47

(I suppose you could argue that bug fixes are "breaking" insofar as they change the behavior of programs that "rely on those bugs")

seancorfield18:06:17

clojure.java.jdbc will only get important bug fixes at this point -- no new features. Unless someone else decides to take over as maintainer and evolve it (but I'd much rather they contribute to next.jdbc at this point).

seancorfield18:06:52

My experiences with many supposed "SemVer"-based projects is that they do still break stuff in patch and minor releases sometimes, and when they bump major versions for breaking changes you just end up with runaway version numbers... so I'm in the "SemVer is pretty meaningless camp".

andy.fingerhut18:06:25

It seems that a reasonable criticism of common practice is that "if they really followed SemVer, they would be at version 72.x.y instead of 3.a.b". That is a problem of how it is followed, and there are marketing/sales/don't-scare-the-customer-away reasons commonly given for "don't increase the major version number if you can rationalize your way out of it".

☝️ 3
seancorfield18:06:24

I will probably bump next.jdbc to 1.1.COMMITS when I merge in either the nested TX control stuff or the multiple result set support (and bump to 1.2.COMMITS when I merge in whichever is the second of those features). I could imagine bumping to 2.0.COMMITS if I added in a whole new set of functionality (such as, maybe, adding in a full DSL for composable SQL queries a la HoneySQL which I also maintain these days).

andy.fingerhut18:06:38

And not only marketing/sales/whatever that engineers often criticize (sometimes with good justification), but engineers themselves do it, without being prodded by marketing/sales/whoever

borkdude18:06:13

I like the .commits so you can just compare the last number for "newer". I might adopt it but then probably counting releases, not commits

hiredman18:06:18

at the limit bumping major version numbers just becomes the commit count anyway

hiredman18:06:42

which is what the underscore guy did for underscore-semver I believe

deactivateduser18:06:17

But that then loses the “breakage” information.

seancorfield18:06:24

I thought he just multiplied the version number by 100? v170.0.0 instead of v1.7.0

deactivateduser18:06:28

i.e. you’re no longer communicating breakage via version label

deactivateduser18:06:37

(which again, I don’t have a strong opinion of either way)

hiredman19:06:28

every change may break some behavior someone relies on, so to be safe bump the major

deactivateduser19:06:30

Only in the sense of “every single version breaks”.

deactivateduser19:06:41

Which is a rather large tax to impose downstream.

seancorfield19:06:47

"every single version potentially breaks"

hiredman19:06:15

only if downstream believes in semver to the point that they don't bother to review upstream stuff unless there is a major version bump

borkdude19:06:57

There are also camps that don't care about breaking, "the type system will just give them a TODO list"

😉 9
deactivateduser19:06:12

@seancorfield if I have to go and do a bunch of legwork to determine, for every single version, whether it contains breaking changes or not, the net effect is much the same as if every version absolutely does contain breaking changes.

deactivateduser19:06:08

But then perhaps living life defensively is ok for some? ¯\(ツ)

hiredman19:06:57

there have been breakages in clojure, like now you will get an error if you use require in the ns macro instead of :require

3
borkdude19:06:24

yeah, or something with :import also changes (a spec macro check will throw)

hiredman19:06:30

which caused a number of projects to have to update

deactivateduser19:06:43

The only breakage I can recall experiencing myself was in 1.10.0, which (given I’ve been using it since 1.2 or so) is a pretty fantastic record.

deactivateduser19:06:00

I’ve been very grateful that I don’t have to be as defensive when using Clojure.

hiredman19:06:15

from the perspective of users, a breaking change, from the perspective of the rhickey, require was always wrong, but just lacked checking

hiredman19:06:52

so maybe a minor bump, a case that was always incorrect now throws an error

noisesmith19:06:22

I assume rejecting :0 and : were considered but weren't important enough to break code that relied on them

deactivateduser19:06:31

@hiredman Right - you’re diving down the “what does ‘breaking’ even mean” arm of the discussion.

seancorfield19:06:37

Going from 1.2 to 1.3 and from 1.3 to 1.4 caused a fair bit of breakage for quite a few folks.

deactivateduser19:06:50

(which I’ve been steering clear of a little bit, since I think that’s the only part of this discussion that has inherent complexity… 😉)

hiredman19:06:09

that is the entire discussion

seancorfield19:06:10

@noisesmith They had an alpha that rejected those and it broke some very high profile libraries that were widely used -- so they reverted that change.

noisesmith19:06:32

man I love it when I wildly speculate the truth

hiredman19:06:54

semantic versioning relies on clear cut delineation of changes into distinct sets

hiredman19:06:03

which is not how changes are

seancorfield19:06:22

But, yeah, Clojure's stability meant we could go to production on 1.3 alpha 7 or 8 back in 2011 and we could take almost every alpha/beta release since then into production fairly safely.

seancorfield19:06:37

When I'm updating versions at work, I'm fairly cavalier about patch updates in Clojure libraries and even minor updates in several of them -- but I carefully review even patch updates on Java libraries.

deactivateduser19:06:01

@hiredman sure, but if one assumes we have some semi-mechanistic way of classifying changes into those distinct sets (and yes that’s a HUGE assumption that perhaps we can visit in future discussions!), there’s a different set of questions that I was more interested in for this discussion, namely: 1. is a version label the right place to communicate those different classes of change 2. if not, what would be used instead (and why have version labels at all, in that case - what else are they for, beyond “communicating change”)? 3. if so, is SemVer a good choice of version label format? 4. if it isn’t a good choice, what alternatives are there, and how are they any better?

hiredman19:06:41

5. what is the cost of semantic versioning

deactivateduser19:06:05

Agreed - cost needs to be considered for all solutions to this problem (including, but not limited to, SemVer).

hiredman19:06:39

a large part o the cost is spent debating which set change falls in to, the other part of the cost is what happens when you assuming you are ok because of semantic versioning and then are not

noisesmith19:06:39

I think the semver problem shares some of the shape of the problem of writing code. You have two targets, a machine and a human, and bad things happen when their interpretations of what they see disagree. One solution to this is to refine the craft of semantic versioning the same way we refine the craft of writing code. Another solution is to not programmatically evaluate version differences, and make it a human only job. I can see the arguments for both honestly.

deactivateduser19:06:50

FWIW I was product manager on a public REST API some years ago, and one of the first things we did (which, to your point @hiredman was difficult and took months of debate) was to lay out a lengthy set of rules for how we rolled version numbers in that API (and yes, we kept all old versions of the API around “forever”, so that we wouldn’t break clients). We even included numerous concrete examples as a “test” of the ruleset. We used a subset of SemVer for that (just MAJOR.MINOR - “patches” were handled behind the scenes, since this was a cloud service and we decided it was counterproductive to expose that level of detail to API clients).

hiredman19:06:57

but like, what if instead of having to have that debate, you just created a new api with every change

deactivateduser19:06:03

What we learned from that exercise is that there is more than one kind of “breakage”, and that what we called “syntactic breakage” was generally trivial to reason about, while “behavioural breakage” was much more complex.

hiredman19:06:21

why have major and minor in a web api?

deactivateduser19:06:56

@hiredman that’s exactly what we did, but the “name” of the new API was simply the “name” of the old API with the “version component” of that name incremented in predictable ways that communicated something to consumers of the API.

deactivateduser19:06:36

Because we wanted to easily communicate different classes of change to clients of the API (both machine and human, which, as @noisesmith pointed out, is a somewhat fraught game).

deactivateduser19:06:38

And as I mentioned, we had already created (and then published) a tome that explained our reasoning for incrementing MAJOR or MINOR.

dpsutton19:06:11

i like the idea of a months long debate figuring out what the rules are for changes. but if the clients don't know those rules what's the point? if they don't know when major / minor might change they have to look at all the changes anyways

deactivateduser19:06:50

They knew - we published (a sanitised version of) the doc.

dpsutton19:06:03

how big was the document?

deactivateduser19:06:54

Not sure if text volume is a food metric for anything, and I’m going from vague memory here (I worked on that product circa 2012, and left that company in early 2016, so it’s all a bit hazy), but my memory is that the sections of the document related to versioning were approximately 1/4 of a ~50 page document. A lot of the versioning material were examples though, which were fairly bulky but low on net-new concepts once the reader became familiar with the patterns.

dpsutton19:06:28

that sounds brutal

deactivateduser19:06:31

I should also mention that at the end of the months-long debate, we’d basically decided to punt on “behavioural breakage”, and focus our efforts on “syntactic breakage” (which as I mentioned above, is basically trivial).

deactivateduser19:06:53

Once we did that the material mostly fell out in a matter of a week or two.

deactivateduser19:06:08

Product management isn’t for everyone. 😉

deactivateduser19:06:00

I should also mention that for about 3/4 of that time I didn’t have a full time architect assigned to the work, so it did go in fits and starts.

deactivateduser19:06:04

And the architect I eventually got basically believed that backwards compatibility was an illusion, and that clients should basically “suck it up” and deal with whatever we gave them in each new version, so “politics” took some time to work through too.

dpsutton19:06:10

oh i would like it. but i'm just thinking on being on the receiving end of that. curt dismissals of "not breaking changes, read para 3 of section 3.4.3.2ii ", and then hoping that the people implementing changes read and understand and hold true to that document as much as the consumer

dpsutton19:06:44

i'm thinking of compiler writers pointing to c standard and writing undefined behavior, we don't care

deactivateduser19:06:03

Right. Little bit less of that behind a REST API, but it can definitely sneak in!

dpsutton19:06:17

i like the effort though. just wondering about where it could go

deactivateduser19:06:34

For REST APIs, I’m a proponent of the “shy geisha” approach to design btw, to help deal with those kinds of issues incrementally over time.

noisesmith19:06:48

did you coin the "shy geisha" term? my google results are pure noise

deactivateduser19:06:48

I doubt it, though I honestly don’t know where I got it from. I even have a sticker of it on my laptop, so it must be out there somewhere… Anyway, if you’ll excuse the crudeness and misogyny, the way the analogy was explained to me was that at one end of the spectrum you’ve got a shy geisha who will reveal as little as possible as late as possible, while at the other end you’ve got a $20 hooker where everything is right there in plain sight from the get-go. The on-prem version of the commercial open source application I was working on at the time was classic open source (i.e. $20 hooker) - customers were encouraged to hack away on whatever they wanted, in order to do whatever they needed to do, and that had created a MASSIVE support problem half a decade in the making. With the (then) new cloud edition of the product launched, my objective was to provide “similar” level of extensibility and customisability, but in a supportable, cloud-friendly way. There was no way our ops team were ever going to allow customer-developed code to run on our infrastructure, so the “hack on whatever you want” model had to go. In hindsight that was the point where we should have realised we didn’t have the right culture to make the cloud product a success. The engineering team (not to mention our customers and implementation partners!) were all used to hacking on whatever they wanted, then throwing support under the bus when they were unable to upgrade, and they just didn’t understand the point of trying to control change. I quit soon after the product got killed, and used the same “shy geisha” analogy at my next gig for several super narrow, super tightly scoped public APIs that were well received and (IM biased O) vastly superior to what I’d worked on previously. Not taking credit btw - I attribute a lot of that to my new company being “closed cloud-native” - they’d never offered on-prem software (let alone open source!), and so never set the expectation with their customers that they could just hack on everything. tl;dr - I don’t claim credit for the analogy, and don’t necessarily like the way it’s phrased - but I do think it’s a valuable way of looking at “interfaces” between different systems (be they client/server via REST or whatever, or in-process library / app)

deactivateduser19:06:00

(apologies for length!)

noisesmith19:06:07

no, it was all relevant - I appreciate how much of your experience you are able to share and articulate and take the time to pass along

noisesmith19:06:54

briefly imagining a more self-critical name for the same pattern, haha. The "nerd" API which info dumps its entire throught process and if you are lucky you can pick out what's relevant, vs. the "chad" API which is cool and only tells you what's relevant

💯 3
deactivateduser20:06:52

I’m too old to understand the “chad” reference, but I appreciate you thinking about a better analogy! 😄

deactivateduser20:06:15

I’ve become increasingly embarrassed to explain it as-is, tbh…

noisesmith20:06:50

"chad" is just a generic "cool guy" who isn't neurotic, and has self confidence, and isn't jumping around trying to get attention

👍 3
noisesmith20:06:43

in other words, he can decide what goes in his API and you know he won't second guess himself and change his mind lightly

deactivateduser20:06:45

Sounds like a better analogy! Now to scrape off this sticker… 😉

deactivateduser19:06:54

Basically - reveal as little as you possibly can, and then slowly open up as you get experience / knowledge / battle-testing etc.

deactivateduser19:06:32

I also had the benefit of picking Mike Amundsen’s brain at various conferences etc.

deactivateduser19:06:40

He’s the guru at this stuff.

deactivateduser19:06:45

(and advocates hypermedia in place of versioning, to throw a cat amongst the assembled pigeons 😉 )

lread19:06:03

while trying to decide on a version scheme for rewrite-cljc, I picked out a few examples I found interesting from Clojure projects https://github.com/lread/rewrite-cljc-playground/blob/master/doc/design/01-merging-rewrite-clj-and-rewrite-cljs.adoc#library-version-scheme-in-progress

dpsutton19:06:01

oh, do not like meander's scheme

lread19:06:16

So when you go with a .COMMITS scheme doesn’t that make writing your changelog a bit tricky?

dpsutton19:06:19

also, so weird that every namespace in meander has the same name epsilon

deactivateduser19:06:23

Another factor worth considering - downstream consumers typically have lots of different upstream dependencies. How does version label fragmentation across those dependencies impose a tax, even though it’s not imposed deliberately by any one of those upstream dependencies?

deactivateduser19:06:47

(another factor in favour of a version labeling standard…)

deactivateduser19:06:28

Obligatory XKCD on the topic: https://xkcd.com/927/

hiredman20:06:24

but if everyone has their own understanding of semantic versioning backed by a 50 page document, then does it make it easier to understand changes in your dependencies?

deactivateduser20:06:34

Learn once, apply everywhere has value (to my last point about adoption).

deactivateduser20:06:20

Inventing your own version labeling format has the unintended consequence of worsening fragmentation, and I know which I’d prefer between learning SemVer (or whatever) once and being able to apply that everywhere vs having to learn a new version labeling scheme every single time I want to use a new dependency…

deactivateduser20:06:38

I mean I lived that back in the pre-Maven Java days, and it sucked.

dpsutton20:06:49

How can you learn once if each dep has a 50 page contract that they may or may not enforce and might be “shy geisha” and decide per instance what a breaking change is

deactivateduser20:06:00

SemVer isn’t 50 pages?

deactivateduser20:06:22

I’m sorry if my REST API example (which also wasn’t 50 pages of versioning documentation) confused the conversation.

deactivateduser20:06:33

And just to agree with one of your points - humans are fallible. But that’s a constant. ;-)