The Changelog: Software Development, Open Source - MAJOR.SEMVER.PATCH (Interview)

Episode Date: June 26, 2024

Predrag Gruevski and Chris Krycho joined the show to talk about SemVer. We explore the challenges and the advantages of semantic versioning (aka SemVer), the need for improving the tooling around SemV...er, where semantic versioning really shines and where it's needed, Types and SemVer, whether or not there's a better way, and why it's not as simple as just opting out.

Transcript
Discussion (0)
Starting point is 00:00:00 What's up friends, welcome back, this is the changelog. We feature the hackers, the leaders, and the innovators behind Semver. We're joined by Predragorevsky and Chris Krycho, two Semver nerds. That's what Jared called them, and they didn't get upset. On today's show, we explore the challenges and the advantages of semantic versioning, a.k.a. Semver. We highlight the need for improved tooling around Semver, where semantic versioning really shines and where it's needed, how types can influence Semver, alternative approaches, and whether or not there's a better way, and why it's not as simple as just opting out.
Starting point is 00:00:47 If you're a Simver nerd like Predrag and Chris, well, this show's for you. A massive thank you to our friends and our partners at fly.io. That is the home of changelog.com. With Fly, you can launch your app near your users. It's good to be near your users, and they'll help you do it with no ops.
Starting point is 00:01:06 Learn more at fly.io. All right, let's send her. What's up, friends? I'm here with a good friend of mine, Faraz Aboukdij. Faraz is the founder and CEO of Socket. Socket helps to protect some of the best engineering teams out there with their developer-first security platform. They protect your code from both vulnerable and malicious dependencies. So we've known each other for a while now, Faras. Well, let's imagine somehow I've landed myself at Vercel. And because I'm a big fan
Starting point is 00:01:42 of you, I understand what Socket is, but I don't know how to explain it to anybody else there. I've brought you into a meeting. We're considering Socket because we want to secure dependencies. We want to ship faster. We want everything that you promise from Socket. How do you explain Socket to my team at Vercel? Yeah, Socket is a developer first security platform that stops vulnerable and malicious open source dependencies from infiltrating your most critical apps. So we do that by focusing on real threats and keeping out all the types of risks that are out there in open source dependencies. Everything from malicious dependencies, typo squad attacks, backdoors, risky dependencies, dependencies with hidden behavior. There's all kinds of risks out there. A lot of reasons why a dependency might be bad news.
Starting point is 00:02:28 And Socket can help you as a developer. Just keep all that out of your app. Keep things nice and clean and pristine amongst your dependencies. I saw recently Dracula. I'm a fan of Dracula. I don't know about you, but I love that theme. Big fan of Zena Rocha. And I saw there was like a misspelling there.
Starting point is 00:02:44 And so because Dracula is installed on VS Code and lots of different places, I saw there was a typo squat sitting there that had different intentions than obviously Dracula did. Is that an example of what you mean? Absolutely. Yeah. Dracula, that's a perfect example. It's super common these days to see that type of an attack where you see a common dependency that you have an attacker just pretending to be that dependency, typoing the name of it by one letter and then trying to get unsuspecting developers to install it. Unfortunately, we're seeing more and more of these types of attacks in the community and they're taking advantage of the trust in open source. As developers, we need to be more aware of the
Starting point is 00:03:21 dependencies we're using and make sure that we're not pulling in anything that could risk the data of our users or cause a big breach at our companies. And so part of that is obviously being more careful and asking questions and looking more carefully at the dependencies we use. But also part of that is tooling. It's really a hard problem to solve
Starting point is 00:03:39 just on your own as a single developer. And so bringing in a tool like Socket can really help automate a lot of that work for you. It just sort of sits there in the background. It's really, really quiet. It doesn't create a lot of noise. But if you were to pull in something that was backdoored or compromised in some way, we would jump into action right in the PR or right in your editor, or even as early as you browse the web. We have a web extension that can actually give you information if you're looking at a package that's dangerous
Starting point is 00:04:07 or if you're browsing Stack Overflow and you see somebody saying, hey, just install this dependency to solve your problems. A lot of times even that can be a way to get the attacker's code onto your machine. So Socket jumps in
Starting point is 00:04:19 at all those different places and can tell you if something is dangerous and stop you from owning yourself. Yes, don't get yourself owned. Use Socket. Check them out. Socket.dev. Big fan of you, big fan of what you're doing with Socket. Proactive versus reactive to me is the ultimate shift left for developers. It is totally developer first. Check it out. Socket.dev. Install the GitHub app to be easy or book a demo. Once again, socket.dev. That's S-O-C-K-E-T dot dev. well we're here with two awesome people that reached out via twitter to talk about
Starting point is 00:05:20 something goes back to our roots jared the very first episode of this podcast was Simvered. Technically. Right? Remember that? It was a 0.01. Yes. And then we got crap because 0.02 was not Simver. But we did it anyways. So we're here with Predrag Gorefsky and Chris Kracho. Welcome to the Change Log.
Starting point is 00:05:40 Thank you. What do you think about the fact that we Simvered or tried to our podcast episode numbers? Pretty sweet, right? We tried. Thank you. time you change formats, it's a breaking change, right? If we apply Rust rules, then, you know, 0.0.x, every release is a breaking change, right? Every one is major. So that sounds good to me. There you go. Technically, before 1.0, you can do whatever you want and the versions are allowed to do whatever they say, per the SEMVer spec. Except in Rust. Yes. And NPM, actually. They both have opinions. Hey, we just walked right into what we're here to talk about. That's right. So we are here, if you haven't read the title, which I'm sure will have Semver in there somewhere, we are here to talk about semantic versioning with two Semver nerds, I'll just call you all that. You can take a fact if you want. Not meant to be offended. Who have thought deeply on this topic. Adam and I, of course, have thought shallowly, I would say. No offense, Adam. Very shallow. Yeah. Yeah, shallowly on the topic. We know it. We've lived
Starting point is 00:06:48 with it. We've seen its failures and its successes. But let's get to know you by way of SEMVer. So, Frederic, you have been working with SEMVer in the Rust community. Is that right? Yes. So, I'm the author of a tool called Cargo SEMVer Checks, which is a linter for semantic versioning. So, when you're about to publish a new version of your package, Cargo Semver Checks can check its API against the previous release and just make sure that everything's looking good, that you haven't made any breaking changes, or that if you have made breaking changes, the next release is major, not minor. So you're not going to break anyone in the ecosystem. Gotcha. And Chris, your work with
Starting point is 00:07:25 Semver is what? Basically twofold. One, my biggest one was I spent a bunch of time, I worked at LinkedIn for about five years. And one of the things I worked on was TypeScript adoption at LinkedIn. LinkedIn is one of the few big tech companies that instead of doing a big mono repo for all of its code, does a bunch of small repos and uses Semver internally. And so as we were looking at how do you adopt something like TypeScript, we wanted a really good handle on how is that going to intersect with our front-end web development ecosystem using Ember.js and using a bunch of repos using Semver internally and then also externally. And so I ended up writing a spec, which lives at semver-ts.org, for what does it mean to try to apply Semver to TypeScript, among other things, because TypeScript
Starting point is 00:08:22 ships breaking changes in what the NPM ecosystem thinks of as minor releases, and also because the type system of TypeScript, and I'm sure we'll get into more of this as we go, but it complicates what it means to make a breaking change in really interesting ways. And that got me running down asking, what does it mean if you have things that borderline on, you know, fancy types that only show up in Haskell or Idris otherwise affecting how your SEMVer spec actually works? which is how Predrog and I ended up talking with each other, in which I looked at, okay, what is everybody doing? What's the state of the art for how to handle versioning, whether you're in Ruby or Node on kind of one end of the spectrum or whether you're in Rust or Elm or when you're out there doing crazy things
Starting point is 00:09:19 and crazy in a very good way here, like what the Unison programming language can do. And just tried to say, here's like what the Unison programming language can do. And just tried to say, here's kind of the range of options, and here's where we might be able to go in the future by pulling in new ideas in computer science research and so on. So I'm at least as much, like, Fredrick and I are competing for who's the nerdiest on Semper here. I think I've gone fairly deep. I'm mostly focused on Rust
Starting point is 00:09:46 and I also have done some prototyping on a similar Semver linter for Python. So I think I've gone deep and Chris has gone wide. There you go. Well, if we were to stay shallow for another two or three minutes and got all of us on board with a foundation of what semantic versioning is
Starting point is 00:10:04 for the lay folk. Chris, you want to define it for people? Yeah. The big idea is that versioning is a tool for communicating with the consumers of your package, your app, whatever it may be. And Semver looked at this problem over a decade ago and said, there are a bunch of emergent ways that the software ecosystem has come up with to kind of describe the feel of these changes over time. It'd be great to give them names that we can all use to talk about them consistently and to give those names some semantics.
Starting point is 00:10:41 And so semantic versioning, where the names are major, minor, and patch for the kind of typical number dot number dot number versioning scheme that, again, emerged organically over the course of decades prior to that. And so a patch version means this has a bug fix in it, and it's otherwise backwards compatible. A minor version means it might have bug fixes and it has some new feature and it's backwards compatible. And a major version means there are breaking changes in this. There might also be features, there might also be bug fixes. And then there's additional metadata you're allowed to tag on to the end. Like this is a pre-release version. So 1.2.3-alpha.0 tells you it's an alpha release
Starting point is 00:11:27 and you can stick build metadata on the end or whatever else you want. But the big and important bit is that semantic notion of what major, minor, and patch mean and the shared vocabulary for talking about them. And I think it's also important to think about what Semver means from a user's perspective, because when I maintain a tool and I have a few hundred dependencies, I don't necessarily want to look very closely at the various different version numbers and think about
Starting point is 00:11:56 what they all mean. But what I do want to be able to do is say, run cargo update inside my Rust project and know that because everyone adheres to what is a breaking change and when it gets published as major and not minor, the updates that cargo is going to make to my lock file are going to be backwards compatible. They're going to result in me still having a working building project at the end of that command. And this is not specific to Rust. I could also do the same thing for the NPM ecosystem and TypeScript. Let's say I could do the same thing for Python. At the end of the day, as a consumer of Semver, I don't care about the numbers. I don't care about the meanings. I just want to
Starting point is 00:12:34 not have to sign myself up for fixing things that I did not intend to break. I ran a command. I wanted some new dependencies that are compatible with my build. And I want that to be the case every time. And notionally, you want that to have the same basic meaning, even if you're jumping across ecosystems like bundler and composer and NPM and cargo and all of these can use the same basic language. And so your experience in principle, we can talk about it in practice, but in principle should be the same, that you can give a specifier to your package manager and say, look, only give me minor bumps to this. And I'll take new features if they come in, and I'll take patch versions for sure if they come in, but don't give me any breaking changes. And NPM should be able to say that, and bundlers should be able to say that, and I as a user should be able to say, okay, cool, this is going to work the same basic way.
Starting point is 00:13:28 Maybe I need to tweak the syntax a little or think about a couple different things, but it should translate across ecosystems more or less. And I love the choice of words there, should be, ominous. I think we'll come back to that. I mean, I think that's the big problem, right? Go ahead, Adam. to that yeah i mean i think that's the big problem right go ahead adam i was gonna say like this might be like the biggest question i have for this whole show and it might be just transcending all the topics but it's like is simver poorly adopted generally or poorly misunderstood which makes it hard to fully adopt without pain because like i feel like that's kind of hard like i don't fully get simver in all the ways there's a lot of y'all are Simver nerds, as Jared lovingly called you guys, you know? And so there's a level of, a depth level that you
Starting point is 00:14:09 all understand Simver, that to me, if I eject and do my job, then I come back in and Simver matters, I've forgotten all the things. And so I just wonder if there's like a lot of people like me, and potentially Jared, you aspire like I do with that same kind of thing is you, you eject, you do your job and you kind of come back and you're like reminding yourself exactly all the implications of Sember. So is it, is it poorly adopted? And then generally to adopt it and to use it, it's hard because not everybody does it the same way. I think it's a tooling problem to be perfectly honest. If any kind of technology requires that you earn a PhD in it before you can be a proficient user, then it's not going to go very far. And the rules of Sember in Rust, in TypeScript, in Python, they're not obvious.
Starting point is 00:14:56 I mean, I've been doing this for years, and there's hardly a week that goes by that I don't learn about a new horrifying way to accidentally cause a breaking change in a Rust project, in a Python project, in a TypeScript project, right? So the fundamental problem here are that the rules are too complex. There's too many of them. It's too easy to break them without noticing. Chris and I have some fantastic examples of doing this in Rust and TypeScript, where the most innocuous seeming change ends up being breaking for some reason that no sane human would ever think of. Right. So the real answer here is the tooling just needs to be good. We can't keep all of these rules in our head and we need tools to do that for us. And so I authored one of these tools.
Starting point is 00:15:43 It's not perfect yet, but it's getting better every day. And I think the name of the game is not to hold ourselves to an unreasonable standard of perfection and just minimize the number of times that a developer publishes a change and then wakes up the next morning to a hundred frustrated users saying,
Starting point is 00:16:00 why did you break my project? Right? Because that's a regrettable change that happened, right? We want as few of those as possible. And maybe we get to zero one day i don't think we're there but i think that trying to get as close as possible to zero is a valiant effort and i think we can make a solid dent in that i would say too like in a in a multi-person project though you also have multiple people that can version or have implications into the versioning. And who determines whether it is a bug fix or a break?
Starting point is 00:16:30 You don't always know either. So you may unintentionally submit something to your repository or make a change, doing a release or somebody does the release for you. I mean, there's a million different ways it could happen. It seems like it's such a brittle process fraught with opportunity to fail. I think that's right. One of the things that I dug into really deeply when I was talking about this at a conference a month and a half ago is exactly that dynamic. That what makes this difficult is those semantics all sound good, but the definition of a breaking change gets fuzzy. So there's a guy named Hiram
Starting point is 00:17:07 Wright who works or worked, I'm not sure if he's still there, at Google, who coined a great law called Hiram's Law and a co-worker of his put it up on the internet. I think it's hiramslaw.com. And it says in basically so many words, given a sufficient number of users of any API, all observable behaviors of the system will be depended on by somebody. And my observation is that the number of users is like a few dozen. It's not many. And that can be used as an argument to say Semver doesn't count or is not sensible because anything you do can break somebody and bug fixes
Starting point is 00:17:47 will probably break somebody. This is actually the reason that TypeScript, the compiler, ships what I would think of as breaking changes in its minor releases because their argument
Starting point is 00:18:01 from a philosophical point of view is any change you make to a compiler breaks someone. So any change you make to a compiler breaks someone. So it's not sensible to have a discussion about what a breaking change is or isn't. Now, I don't actually agree with that, but I do think it gets at something really important, which is that ultimately we're not dealing in something that's purely a technical problem to be solved. Because ultimately, again, versioning is about communication, right? It's about that conversation you're trying to have with your
Starting point is 00:18:30 end user, often a conversation you're trying to keep as low bandwidth as possible, where they just see version number change, what do I need to think about it before they even go digging into your release notes, so that they can say, oh, yeah, this one should be safe. Let me try it. Bump worked. Cool. Great. And I move on with my day. And so you have this tension of saying, what's a bug? If my bug fix, which is a real bug fix, breaks my entire user base, do I call it a bug fix anymore? And I think what that gets at is that you still need human judgment in there and what you want is for the tool to catch all the cases which are knowable. So all the cases where you can say no for sure this is a breaking change you want the tool to tell you that and then additionally you're
Starting point is 00:19:18 going to have things on top of that which might also be breaking changes, where you're saying, okay, this thing might not be a breaking change in terms of that ridiculous 10,000-word spec I wrote about TypeScript or in terms of what cargo semver checks can catch today, but I'm looking at it and I'm saying, this one's going to break 96% of my users. I'm going to go ahead and call it a breaking change because I'm the human in charge of this and I care about my users and I'm going to make that judgment call. So it's
Starting point is 00:19:49 sort of a start with the things you can prove or know based on tooling. And that eliminates a massive amount of the argument or confusion in the space because you can just trust the tool to do it. And then pull in the human judgment and say, does this bug fix feel like a breaking change? Okay, then it is. Because again, communication tool above all. And this is interesting, because I think it's sort of the opposite of many other linters, where false negatives are actually okay. Not only are they okay, they're going to happen
Starting point is 00:20:25 no matter how we feel about them, right? Until we solve that pesky halting problem, right? No SEMVer checker can catch everything. Human judgment is always going to be necessary. What we really strongly don't want is false positives, right? The tool saying, I found a breaking change
Starting point is 00:20:42 where that is not the case. So we want our tools to be extremely confident when they report something. And it's okay if they don't catch everything. And that's the approach that cargo semver checks takes. That's the approach that my semver linter for Python takes. I just think that's the correct approach. And that's not always the right approach for every flavor of linter, right? Right. Sometimes the false positive is safer. But here, I tend very strongly to agree. And a good example is like what Elm does. Elm has a very conservative and fairly minimal approach to the way it thinks about it.
Starting point is 00:21:16 It basically just looks at the changes when you do something at a type level. You know, did this add a parameter to the function? Did it remove one? Did it add or remove a field on a data structure? And very simple checks like that. And that's all it does. But it does enforce that
Starting point is 00:21:31 and it's built into the package publishing flow. And I think that's great. Again, it leaves room for the human judgment, but it doesn't, it also sets a conservative baseline that's guaranteed to be accurate.
Starting point is 00:21:43 Like it's never going to false positive you because any of those changes can be statically known. Nope. A hundred percent. You made this change. That's gonna, that's gonna host somebody. Right.
Starting point is 00:22:07 What's up, friends? I'm here in the breaks with David Hsu, founder and CEO at Retool. If you didn't know, Retool is the fastest way to build internal software. So, David, we're here to talk about Retool. I love Retool. You know that. I've been a fan of yours for years, but I'm on the outside and you're clearly on the inside, right? You're on the inside, right? I think so. Yeah, I'd say so. Okay, cool. So given that you're on the inside and I'm not on the inside, who is using Retool and why are they using Retool? Yeah. So the primary
Starting point is 00:22:37 reason someone uses Retool is typically they are a backend engineer who's looking to build some sort of internal tool and it involves the frontend. And backend engineers typically don't care too much for the frontend. They might not know React, Redux all that well. And they say, hey, I just want a simple button, simple form on top of my database or API. Why is it so hard? And so that's kind of the core concept behind Retool is frontend web development has gotten so difficult in the past 5, 10, 20 years. It's so complicated today. Put together a simple form with a submit button, have to submit to an API. You have to worry, for example, about, oh, you know, when you press the submit button, you got to bounce it or you got to disable
Starting point is 00:23:15 it when it's, you know, is fetching is true. And then when it comes back, you got to enable the button again. When there's an error, you got to display the error message. There's so much crap now with building a simple form like that. And Rachel takes that all away. And so really, I think the core reason why someone would use Retool is they just don't want to build any more internal tools. They want to save some time. Yeah, clearly the front end has gotten complex. No doubt about that. I think even front-enders would agree with that sentiment. And then you have back-end folks that already have access to everything, API keys, production database, servers, whatever. But then to just stand up Retool, to me, seems like the next real easy
Starting point is 00:23:51 button because you can just remove the entire front end layer complexity. You're not trying to take it away. You're just trying to augment it. You're trying to give developers a given interface, that's Retool, build out your own admin, your own view to a Google Sheet or to the production database, all inside Retool. Let Retool be the front end to the already existing back end. Is that about right? Yeah, that is exactly right. The way we think about it is we want to abstract away things that a developer should not need to focus on, such that the developer can focus on what is truly specific or unique to their business. And so the vision of what we want to build is something like an AWS, actually, where I think AWS really fundamentally transformed the infrastructure layer.
Starting point is 00:24:40 Back in the day, developers spent all their time thinking about how do I go rack servers? How do I go manage cooling, manage power supplies? How do I upgrade my database without it going down? How do I change out the hard drive while still being online? All these problems. And they're not problems anymore because nowadays when you want to upgrade your database, you just go to RDS, you press a few buttons. And so what AWS did to the infrastructure layer is what we want to do to the application layer specifically on the front end today. And for me, that's pretty exciting
Starting point is 00:25:09 because as a developer myself, I'm not really honestly that interested, for example, in managing infrastructure in a nuts and bolts way. Now, I would much rather be like, hey, you know, I want an S3 bucket. Boom, there's an S3 bucket. I want a database. Boom, there's a database. And similarly, on the front end or in the application layer, there is so much crap people have to do today when it comes to building a simple CRUD application. It's like, you know, you probably have to install 10, 15, maybe even 20 different libraries.
Starting point is 00:25:35 You probably don't know what most libraries do. It's really complicated to load a simple form. You know, you're probably downloading almost like a megabyte or two of JavaScript. It's so much crap to build a simple form. And so that's kind of the idea behind Retool is could it be a lot simpler? Could we just make it so much faster? Could you go from nothing to a form on top of your database or API in two minutes? Well, we think so.
Starting point is 00:25:56 Yeah, I think so too. So listeners, Retool is built for scale. It's built for enterprise. It's built for everyone. And Retool is built for developers. That's you. You can It's built for everyone. And Retool is built for developers. That's you. You can self-host it. You can run it in the cloud.
Starting point is 00:26:09 A custom SSO, audit log, SOC 2 Type 2, professional services. Starting with Retool is simple, fast, and of course, it's free if you want to try it right now. So go to retool.com slash changelog. That's R-E-T-O-O-L dotcom slash changelog. Let me make two somewhat contradictory statements, which I both think are valid. The first one is that I have been a user of Semver tooling for many years in roughly three different Semver oriented camps, Ruby, Elixir, JavaScript, as just an application developer. And roughly speaking, and I know Semver enough to realize like major, minor patch,
Starting point is 00:27:00 what should be safe? What should I check? Blah, blah, blah, blah. I've rarely been bitten by these problems as a user. Now you guys are at the library level and you're at the tooling level. So very generally, the system isn't terrible. We are talking about its downfalls and we are nitpicking and there are many ways that it breaks. And the problem is we didn't know it broke until it's too late. In fact, we didn't think it was going to be a break. And so we communicated wrong. Like these things are all issues and ones that we all bund up against in some places better than others.
Starting point is 00:27:32 But generally speaking, I think it's been somewhat of a win. That being said, with the tooling situation, Frederick, that you're talking about, and with our desire to constrain ourselves from miscommunicating are we finding the local maximum right are we are we trying to polish a turd so to speak are we is there ever a solution to this problem is it worth saying you know we can try to clean up the world that we're living in or we can just invent a brand new world is there just is semver just fundamentally broken and we're not going to fix it? And we could probably just do versioning in a different way. Some people just ignore it altogether.
Starting point is 00:28:10 Your thoughts? I actually have some hard data to share on this. So about a year ago, four enterprising college students and I embarked on a journey to figure out how good the state of SEMVer compliance is in the Rust ecosystem. Now, Rust, statically compiled language, you know, biased towards systems, you'd expect, you know, if anyone is very hardcore about adhering to Semver properly, it should be Rust, right? Yeah, for sure.
Starting point is 00:28:36 So what we did is we took the top 1000 most downloaded Rust libraries, right? So these are extremely popular things like, you know, Surdy and Tokyo and things like that. Things that multi-billion dollar companies depend on, you know, easily, right? And they're developed by some of the smartest, most experienced people in the ecosystem. And we scanned 14,000 of their releases total. We found that more than one in six of them has unintentionally shipped a SEMVer violation that we could find. And we found that more than one in six of them has unintentionally shipped a SEMR violation that we could find. And we found that more than 3% of all the releases contained at least one SEMR violation that we could detect and could have prevented. 3% of every release means that on average, if I run cargo update once every 10 days, my project is broken once, right?
Starting point is 00:29:25 Like every 10 days that I run cargo update, I've updated one dependency that will introduce a breaking change. Now it's unclear whether I actually use the part of the API that ended up being broken by that breaking change or not, right? So I might get lucky and it might be okay. But now let's think about this on a population timescale, right?
Starting point is 00:29:42 There aren't 10 people depending on these libraries, right? When these breaking changes happen, they break the entire ecosystem. And so thousands of people have to spend their time figuring out why the heck the build is red all of a sudden. And then maintainers on the other side have to, all of a sudden in an unscheduled, highly stressful, highly charged environment,
Starting point is 00:30:09 publish an emergency patch that either undoes the thing or whatever it was. Imagine if it was bundled with a security fix. Now, all of a sudden, the pressure is even worse, right? So as a user, when I run cargo update, I don't want to be broken. As a maintainer, when I run cargo publish, I don't want to break people. As a member of this ecosystem, I want the people that don't have a lot of time on their hands to not spend their time pointlessly fighting tooling in one way or another. I want all of the maintainers of all of the libraries that I depend on to not have to worry about were they broken or were they going to break somebody.
Starting point is 00:30:40 So the thing here that we're talking about, you know, sounds like a small effect, 3%. Yeah, whatever, rounding error, maybe it's okay. But the thing is that it adds up. These little bits of friction here and there, they really add up when you consider the large population and the long time horizon of these projects and how many times, you know, these projects get downloaded and used every week, right? So even though the individual impact on
Starting point is 00:31:05 a single person's day is probably next to zero, multiply that out to the number of people that depend on that software, and all of a sudden, the impact is pretty darn significant. Okay, so you're saying it's not good enough as is and tooling can improve. Can it get us into a from 3% down to a minuscule fraction in which we can live with this? Chris, your thoughts on that? I think the answer is yes. And one of the reasons that I'm more bullish on sticking with SEMVR and putting tooling around it is because I did survey the rest of the world, as it were, when it comes to versioning. And there are a lot of approaches that just say, ah, these problems with SEMVR are fundamental.
Starting point is 00:31:45 Scrap it. One of them, SoloVer, is just have one version number. It's one, two, three, et cetera, just go up. And that has a certain appeal to it, but the actual fundamental issue there hasn't changed. All it does is take the burden off of the maintainer of a library and put it on all of the users. It says, okay, now you're responsible anytime any one of your dependencies changes, including transitively, anywhere in your dependency tree, to go read the release notes, which tend to encode things like breaking changes in the release notes. Because, again, communication problem, right? We want to know what did this do? And so also as an aside,
Starting point is 00:32:29 all of those proposals include things like, well, you can also stick like pre-release numbers on the end. And I'm like, but what, hold on, hold on. It seems kind of like we're backing our way back toward this whole Semper thing now, aren't we? Shouldn't your pre-release just be another number? I think there is a sense in which there is a maybe fundamental local maximum. Like maybe it's local, but the hill's so big that
Starting point is 00:32:55 we're not going to find a different path. Could be wrong about that. But when I go looking around, the things that seem like they might change the calculus here don't so much eliminate the value of SemVer as they do build on it. So a good example here is what the Unison programming language does. Pretty small language, but it is aimed at industry. It's not pure research. And they do something that's really wacky in the best way. You don't store your code as plain text. Instead, they take advantage of the fact that they're a
Starting point is 00:33:33 pure functional programming language with really well-specified semantics. And they say, okay, we can take your code, normalize it, hash it, and store the compiled output of it with a pointer to it, which means a whole bunch of interesting things. But for the purposes of versioning means when I make a breaking change, the original version is still there because that hashed compiled version of it got committed to a database instead of to plain text. And that database version is what anybody who depends on it sees. So when I add a new parameter to my function, the consumers are still pointing to the old function,
Starting point is 00:34:14 which means they can pull this update and say, okay, I can progressively switch over to the new function signature, but I can do that at will and the two can live next to each other. And because it is a pure functional programming language with no side effects that aren't managed off in the runtime, et cetera, et cetera, you know, leave all that aside. Suffice it to say, because of that choice, they can just, quote unquote, ship a breaking change
Starting point is 00:34:35 without it ever breaking anyone. The reason you still want Semver here, though, is because Semver is a communication tool. And so Semver lets you say, okay, there are these new features in the library. Here's a bug fix. You're going to want this one. And even though that means you need to actually go update which compiled version of this function you're pointing to, you're getting data from that. And when you go to publish your library,
Starting point is 00:34:59 you want to be able to use that information. Even knowing that it's not going to break your users in the same way, it does let you then say, oh, I didn't actually mean to make a breaking change here. I wanted this to be compatible and to just keep working forward. So things like that, I think, are pointers in the right direction. There's also a couple papers out there from folks at the Nova University of Lisbon who are asking, like, what happens if you bake versions as types into Java? Java because it's the kind of default language to do this kind of research on. Their proposal is very interesting from a type theoretic and versioning perspective and would never get adopted in industry in a million years because it's just way too much boilerplate. But it does the same thing we're talking about. It bakes this notion of backwards compatibility in, in a way that I think would, if you were going to actually ship
Starting point is 00:35:57 something like that in an industrial programming language, you would actually want SemVer as basically how you do it. And their type system that they slap on top of Java effectively encodes Semver with keywords. It's like upgrades and replaces and things like that. So I think there's work to be done here, but I don't think it's going to be in the near term for one. So we're going to need the tooling. And even if and when we see
Starting point is 00:36:25 something like that type system on top of Java or what Unison is doing becoming more widespread, I think those kinds of things lower the risks in really interesting and important ways, but they would still really benefit from the kinds of tooling that we're talking about. They also, though, highlight, I think, one of the things that's easy to miss in these kinds of discussions, which is a lot of times people like me, who are type theory nerds, et cetera, like to go looking for that kind of solution to a problem. It has two limitations. One is that's never going to work for Ruby. I say never, but like you could imagine a world in which type adoption for Ruby is at 100%, but that world seems very unlikely to me. Not least because a lot of people who love Ruby love it because it's dynamically typed.
Starting point is 00:37:18 And second, doing all of those things purely at that, like let's bake it into the type system level, has costs. Because it turns out that that itself then becomes a thing that you need to think about in terms of the versioning of your language. Because one of the things that shows up is that the more foundational whatever your tool is, like if you're an app and you just have consumers, it's not that big of a deal. Your versioning is basically purely marketing. If you're a library, you have a bunch of apps that use you and maybe some other libraries. If you're a framework that everybody else builds on, how well you do this now affects everybody else in the entire ecosystem. If you're a programming language, you're kind of doing it at the maximum level and you still have to communicate those versioning constraints to
Starting point is 00:38:01 other people. And the more complicated your type system is, the harder it is to actually understand what the implications are for versioning. So the tendency that people like me have to say, ah, bake it into the types, then it'll be rigorous and checked forever, can actually undermine your net goals here because now you've made it harder to think about this fundamental communication problem.
Starting point is 00:38:23 And this is an area where Chris and I had an interesting discussion that made us feel like this would be a good podcast topic. I agree with him that building versioning into the type system of a language like Ruby or Python is not the way to go here. But that doesn't mean that we can't build Semper tooling for dynamic languages. And in fact, I've built a Python semantic versioning linter that's in closed beta with a few friends right now. But if someone listening to this wants access, find me on social media, and I'm very happy to send it your way. The core idea is that
Starting point is 00:38:57 when we as programmers look at a piece of code, and a change to that code, we have a set of rules and heuristics that we run in our minds to determine if something is breaking, right? A public function got deleted. A function signature changed. Now it takes a different number of arguments. A default got, you know, went away from somewhere. There's nothing stopping us from encoding those rules in a machine-checkable way and just have the computer go through that checklist and make sure that we didn't mess anything up, right? Now, this tool isn't doing anything differently to what we were doing.
Starting point is 00:39:32 And if it finds nothing and we find nothing, then great. Just ship it as a miner and everything's fine. But on the off chance that we haven't had our caffeine that day or we're just tired or, you know, we have something else going on in our mind. And we miss one of those things, and the tool catches it, that's just pure win. Right? So it's those cases that I'm very interested in catching with tools, it's fine, they're never going to be perfect. I'm not perfect either. I'm just very interested in finding the spaces where my imperfections and the tool's imperfections happen to not overlap
Starting point is 00:40:05 so that at least one of us catches it. I mean, I like that because it's pragmatic and because it seems achievable. I mean, it's just work and it's probably hard work and I'm glad you put some of that work in, but it's really like taking that 3%, which is probably a high watermark considering it's the Rust ecosystem.
Starting point is 00:40:21 It's probably a much higher percent in other places. It's actually much higher in Rust as well because those are just the issues that we found by running the tool. If you use the tool, the 3% goes to zero because the tool would have caught all of that and prevented it, right? So that number could only grow even in Rust
Starting point is 00:40:38 because the tool gets better every day. How comprehensive is the tool? Do you have a set number of things you're checking and you're just adding to that constantly? How's it work? Absolutely. So we have about 80 lints right now. So that means there are 80 flavors of breaking changes for which if they happen, we could construct a program that gets broken by that breaking change. So we could constructively prove that something bad happened. Either that program doesn't compile anymore or it triggers undefined behavior so it would be caught by Miri Rust's undefined behavior scanner or something like that. So something very obviously goes wrong based on the thing that we found and we can offer constructive proof of that. I also have a list in an issue on the project's GitHub of like
Starting point is 00:41:22 150 more things that we should catch that we don't catch yet. And on a fairly regular basis, new contributors to the project come in and they go, ah, this bit me last week. I'm going to check this thing off the list. And they come in, they write a lint, they open up a request, we merge it, and the next release,
Starting point is 00:41:41 that problem is never going to be a problem for them or for anyone else ever again, so long as they remember to run the tool in CI before publishing or on their local machine, if that's how they publish. So it's more of a never again kind of a tool and not really a perfectionistic idealistic sort of approach. Yeah, exactly. Yeah. Yeah. I love it. So that's that knocks off Rust, though. And you've got something you're working on in Python. But of course, there are many programming languages,
Starting point is 00:42:09 Extant, and many ecosystems, some of which nominally do Semver. I mean, there's also the ones that just don't do it. I mean, that's the other thing with, first of all, you have to buy into Semver, but then also the communication of how you do Semver. Forget the tooling. I'm sure there's different ideas of what Sember is,
Starting point is 00:42:27 even in the minds of one person. You know what I'm saying? Yeah, we do Sember, except for the majors, because we want to have a marketing opportunity. And so we throw it out the window when it comes time to market. Because that's a communication problem as well, and one that many people dislike Sember because of. They can't market their big releases. I actually think that is the biggest unsolved weak point of Semver, like more than the
Starting point is 00:42:51 philosophical, what is a bug fix problem? Because that one's really one that we can just agree, kind of make a definition, make a contract and run with it. Everybody can get on the same page. Maybe I don't like the contract you picked, but I can at least understand it and follow it. The fact that versions are also a tool for marketing makes it very difficult for projects which do SEMVR and also do breaking changes to figure out how to use their marketing. Now, Rust itself as a language has just said, oh, we'll never ship a breaking change, problem solved. We'll tackle marketing in entirely other ways. Ember.js famously is like the most Semver project ever and has struggled enormously with this because the JavaScript
Starting point is 00:43:38 community looks at big releases and thinks, ah, this is Ember JS5 or Ember JS6 coming up in however many months from now. Sweet, big breaking, big cool features because when you look at React 19, you get a bunch of cool features with it, a ton of stuff and some breaking behaviors that they slowly built up to over the course of the React 18 lifecycle.
Starting point is 00:44:02 But then you get to Ember 5 and it says no new features. And you say, I'm sorry, what? Because Ember says, no, the only thing we use major versions for is removing deprecated code. And in some ways that's very powerful because it means that you can think about how you schedule in updating to minor releases, updating to long-term support minor releases. And then, okay, if an Ember release comes every 18 months, I can just bracket in. I need to have these deprecations cleaned up by time X,
Starting point is 00:44:36 whatever that ends up being. That's really powerful. And you also know that you're not coupled to the existence of these new features for I have to get through these breaking changes first. That's great, but how do you tell that story? And I would put it as a former Ember Framework core team member who thought about this a bunch. We never figured it out.
Starting point is 00:44:56 Like Ember tries to use additions to do this, which is similar to Rust's notion of additions. It's this kind of big, everything comes together at a point in time. We've updated all the documentation. All the APIs are coherent. Everything is in a place where we've made this really significant change to the ecosystem. It's a good idea that in the Ember case, I don't think has worked. I think it has sort of worked in Rust's case because it comes with other trade-offs around being able to make changes to the surface syntax of the language that are opt-in but breaking and backwards compatible.
Starting point is 00:45:28 That's a whole different podcast and a different discussion. Super cool, worth talking about. But I don't think we have a solution for this particular dynamic of how to, if we're going to SemVer seriously, how do we communicate, here's a big marketing moment. Ember's Editions is, I think, a step in the right direction there. But I've sometimes wondered if we don't need like marketing version as just a totally different thing. And I think that's what Editions points at. But I don't know. I think it might also be a matter of seeing somebody with enough scale try it. Because Ember's very small. It has a lot of great things going for it. But if you're 2%, 4%, whatever of the broader JavaScript ecosystem trying that kind of thing, whereas if React did it and did it that way, I think it might stick more in people's minds of, oh, this is how this works. Now, I don't expect the React community to try that, but you could imagine that a bigger project might be able to influence the way people think about versioning more effectively by
Starting point is 00:46:34 taking that swing. But it might just also not work and we'd have to try something else. I also have a maybe strange idea for how to maybe fix this. What if we made breaking changes not actually require major versions and still adhere to December? So we could actually reserve major versions for marketing only. Crazy. I know. Hear me out. And just to be clear, I am not planning on building this until there is a lot more funding flowing to cargo Sanford checks and the other projects I'm working on. But it is a genuine idea that I think could work. Imagine that we could detect with very good confidence, breaking changes in a mechanical fashion. And based on the change that we see, right? Like this argument is now necessary and functions as opposed to previously we could pick up a default, whatever.
Starting point is 00:47:27 If we could generate code mods, rules for how to change code so that it's compliant in the new version and preserves the behavior of the old version, right? Where when I run cargo update or the equivalent in NPM or PIP or poetry or whatever, in addition to picking up the new version, it also goes in and tweaks my uses of the code
Starting point is 00:47:50 that it updated dependencies for so that I'm no longer broken, right? This still satisfies my objective of the build is still green before and after, right? And there was a breaking change in the API, but that breaking change only affects me the next time I write a piece of code that uses that API and not any of the existing uses. So in my book, if you ship code mods that are of sufficient quality for all of the changes that are breaking, that does not necessitate a major change to tier December.
Starting point is 00:48:22 Because no human action was involved in making that change. That change is completely mechanical, right? And at that point, we can say major versions are for marketing and everything else can be minor. Now, obviously, this requires a bunch of tooling and infrastructure that we don't have and tooling and infrastructure that I would love to build if someone wants to send a lot of money to my GitHub sponsors page. But I think it's a viable future that we could have
Starting point is 00:48:48 that solves both this problem and a lot of ergonomics and usability problems of SemVer as well. Yeah. That's interesting. It's a cool idea. Very much feels like a boil the ocean kind of a thing. That's what people said about cargo SemVer checks when I started it. There was a lot of this will never work. I think one of the things that strikes me about that is that it works. about cargo sound for checks when I started it. There was a lot of, this will never work.
Starting point is 00:49:07 I think one of the things that strikes me about that is that it works if and only if you can make it, as you said, genuinely 100% on the code modability side of it. And so I think it gets at the human communication dynamic piece of it again. One of the things I think about a lot is, if this operation used to be, you know, to use the standard performance language O of one, constant time access to get something out of this data structure. And now I made a change to the
Starting point is 00:49:37 performance of that data structure that gives it way better memory characteristics, but now makes it O of N. So it scales with the size of the number of items in the data structure. And the surface level API didn't change. That's a breaking change in my book, because you can radically impact the performance of your end user systems by doing that. But it's not going to be statically catchable by the kinds of things that could code mod it because the API hasn't changed. And so I think there's an interesting chat. Like I think what you just described is good
Starting point is 00:50:12 and it's actually kind of the improved version of what Rust and Ember and some other JS frameworks have tried to do of when we ship a deprecation, we also ship a code mod with it that moves you to the new API. And that goes a long way, especially if it's one of the ones that's 100% rather than like 80%. And now you have to do the last 80% yourself. And yes, listeners, I said 80% both times on purpose,
Starting point is 00:50:35 because that is my experience of how that goes. You solve that 80% in the last 20% takes another 80% of the time. I think the other challenge there is making the thing trustworthy enough that people feel like it's safe to do that as part of their NPM update or cargo update or whatever it is. And I think you probably have more leverage to do it in an ecosystem with types
Starting point is 00:51:03 than one that is without types for the simple reason that it's easier to be confident that you got it right with that code mod. Not necessarily impossible in Ruby or JS or whatever, but easier. Hmm. Hmm. It seems like for incremental adoption,
Starting point is 00:51:23 I like the idea, Prederick, but it seems like for that,, I like the idea, Predic, but it seems like for that, just simply adding a prefixed, I mean, Chris is kind of joking, but maybe would work kind of like, why don't we just add another number that if your version has four numbers, the first one's marketing.
Starting point is 00:51:39 If it has three numbers, then it's just the old style. And so you could just have that and not having to fix that problem of the breaking change with the Codemods thing, which I still think would be a worthy goal and one that you should definitely get sponsored by somebody to work on.
Starting point is 00:51:56 But it seems like it's really far away from something that we could use. Would it always remain one in front of that? So if you had four numbers, would the number one or number two be like... Because that's the thing too with marketing is not to say negatively about those folks but they're not generally in the minutiae like we are here and there's a thought process break where what they think is marketing is simply what is acceptable what's praiseworthy what's celebratory not so much practical and pragmatic in the application state. Right. So it's really just window dressing.
Starting point is 00:52:26 It's not really useful. It's just there to be there to represent. Which is why it's optional. Right. There's almost a sense in which the ordering is the opposite of what we want for marketing reasons. True. In that the minor release, which comes along, whether it's on a cadence like Rust or Chrome or whatever, where it comes out on a predictable timeline or where it comes out whenever it comes out. The minor release, if you think about the SemVerse semantics, is actually the marketing excitement. It's the we got new stuff moment.
Starting point is 00:53:02 And yet it's the second slot. Right. got new stuff moment. And yet it's the second slot. And the something broke is the first slot because there's a good reason for it, which is it's the one that's going to hurt the most. Hopefully the other ones won't hurt, but doing the breaking changes is going to be some work. That's why it's breaking. I don't have a solution for that, but it does feel like they're backwards that way. And in fact, when I was making slides for that talk, one of the things I noticed is that when I went to explain it,
Starting point is 00:53:28 and I think I did this when I was talking about it earlier, you want to explain the order upside down. You want to start with patch and say a patch is a bug fix. And then a minor is a feature or a bug fix. And then the major is breaking changes and maybe also a feature or a bug fix, but you almost end up kind of backwards from the Semver ordering. And I do kind of wonder
Starting point is 00:53:53 if the move, you know, to your question earlier, Jared, about is Semver even the right shape? I think if we were to take a different swing at it, we want to keep all of those bits, as it were, of data. But we might want to find some way to treat them as a different kind of ordering. And getting really nerdy here for a sense, it's not clear to me that when we think about like partial orders or total orders in a deep type theoretic sense, that that's actually quite the right model for versioning. And the marketing part becomes a piece of that because the marketing thing may really be very distinct from when breaking changes land. And both of those are really important bits,
Starting point is 00:54:41 but it feels really weird to say that I have version two dot where that's the marketing version. 4, where there have been four breaking changes as part of marketing version 2.0, that feels weird. And then all of these other feature numbers along the way as part of it. And maybe just thinking about different ordering schemes or ways to kind of decouple those further could be a part of the future here. You need all of the bits though. You need the marketing bit somewhere
Starting point is 00:55:11 and you need the breaking change bit somewhere and you need the bug fix bit somewhere. One more thing that's interesting is that there'll be names. So like Dragonfish, for example. You know, not only is it, and I'm talking about trunas here in this case trunas scale uh 24.04 which actually is not semver it's it's i've learned today it's called calver it didn't really even it makes sense but yep i didn't consider the fact that it's the 24th year in the fourth month so they have a release
Starting point is 00:55:41 cycle everyone understands that that's also they've adopted the Ubuntu way as well which is you know year and month and they have a release schedule but they also call it a name and in the case of Ubuntu they have certain names I think they're all based on Pixar if I recall correctly and then Dragonfish in the case of TrueNAS scale that this is what they named it so they add one more nomenclature, which really is their marketing term. So I wonder like, is the fourth number really required? Can you just leverage a naming schema? That's what Ember has tried to do. And again, that's the question of like,
Starting point is 00:56:16 does that work or not? I think Ubuntu is interesting as an example. I'm not in that ecosystem anymore. I used to run Ubuntu for a bunch of things, but I never, even when I did, I don't remember remembering the names very well. I remembered the cadence, but Calvr's interesting,
Starting point is 00:56:33 Calvr being calendar-based versioning, because once again, you're back to read the release notes as your mechanic for did this break something that I depended on? Because Calvr tells you when something happened, but it doesn't tell you what happened then. It's in that way, kind of like Solover, which says even less.
Starting point is 00:56:53 I like Calvert better because it at least gives you a date that's useful. But both of them have the problem of they basically reduced to something happened, right? But what? What happened is what I want to know. And I think the big name for it the branding name for it as you're saying adam it helps because then you can actually use
Starting point is 00:57:13 something and i was incorrect i think it's debbie and that leverages pixar characters right jared toy story was where they started i'm not sure if they moved on from there and i don't know i think abuntu actually has a double name and i'm not sure i'm trying to figure out quickly because i messed up yeah they're like alliterative animals, aren't they? Yeah, alliterative animals is exactly it, I think. All right, WordyWordHog was 4.10. WordyWordHog, I remember. But I do agree.
Starting point is 00:57:33 I never go back and remember which one was. I know Sid, because that's the experimental branch. That's a great name for that. But then the rest of the Debian releases, it was like, was this Woody? Was this Buzz? Was this I don't know? Because they're important as they come up. But historically, I just forget which one's which.
Starting point is 00:57:50 Because you have a bunch of them over time. So they kind of lose their meaning. I think Calvary really has a place with products less so than with libraries. Because I think just like knowing, it is nice to know when was this product released? Because it's right there in the version number. But I agree, it really doesn't tell you much about that release which is fine for products because you have all kinds of other things around them but with libraries we want to know more details right like these are this is like business not fun kind of stuff right like we don't want to
Starting point is 00:58:20 break our businesses and for libraries and frameworks I think of Semver as Calver with an extra optimization slot, in a sense. If every Calver release, your release twice a year is allowed to make breaking changes, right? That's just like, as if you updated the major number in every release. But every so often, there's a release that does not make any breaking changes. Maybe it's just some patches, maybe it's some new features that don't affect existing functionality. If you tell me that you've made such a release, I don't have to pay as much attention when upgrading. I will expect that I can just let my package manager from my ecosystem handle it for me
Starting point is 00:58:59 with no action from my part, right? Now, you could be conservative. You could say, I'm not sure. Maybe I've made a breaking change and release a new major every part, right? Now, you could be conservative. You could say, I'm not sure, maybe I've made a breaking change and release a new major every time, right? And that still adheres to SEMVR. That also happens to be Solover in practice. But if you tell me that you've made breaking changes
Starting point is 00:59:17 more often than strictly necessary, then you're shifting the effort on my part, like Chris was saying earlier, right? The more you can tell me that based on your gut feeling, you have not made breaking changes. And ideally based on the best available tooling for your ecosystem, you also have not made any breaking changes.
Starting point is 00:59:35 The more often I'll be able to patch feeling confident about it and ideally not spend six hours then chasing type errors or worse, you know, misbehaviors in a system that I've deployed to production, right? So I think Semver is just an optimization over what we could get otherwise, because I optimize away the necessity of me reading the release notes religiously for every one of the 400 odd dependencies that my project depends on.
Starting point is 01:00:01 I do think that is suggestive, though, of the value of calendar-driven releases. I think predictability inversion is actually really, really helpful in that regard. So the fact that TypeScript releases basically quarterly is really helpful for planning around it. The fact that Rust releases every six weeks is really helpful for planning around it. And it's helpful for all the teams who work on those projects because it gives them a schedule. But it also means that you can think, okay, maybe we don't have the appetite as an organization to take a TypeScript update
Starting point is 01:00:33 every quarter. But knowing that they come out quarterly, I can bundle it up and say, I'm going to do this every six months or I'm going to do this every year or whatever the cadence I choose. And it's very difficult to do that in ecosystems where that kind of schedule doesn't exist. So historically, I don't think C-sharp has,
Starting point is 01:00:54 and they may have shifted this in recent years, but it wasn't the case for a long time that there was a predictable cadence. They came when they came. And that meant you couldn't plan around that. For a long time, Ember didn't do that and you couldn't plan around that. For a long time, Ember didn't do that, and you couldn't plan around it. React certainly doesn't. React 19 comes when React 19 comes. And the entire ecosystem gets to go, woo, let's figure this out now. Okay, this is going to be a ride. I think having a schedule, one of the things that Predrog just said they got me thinking
Starting point is 01:01:20 is it would be really interesting if your major version intentionally adopted the calendar versioning nomenclature, because that would pull you out of the frame of thinking about it as a marketing version. Because 24-04, like 24-04.01.2 doesn't make you think, ah, the marketing version 21-04, like that's not a marketing version, no. And that might be enough of a shift. And you could still codify that like this is a system that tools know how to process as SEMVer-ish in shape because it's still predictable. It's still month year with a dash in between them.
Starting point is 01:02:04 It's trivial to parse. But doing that might give you, as an ecosystem, a chance of much more clearly distinguishing, okay, this is a timed release that bundles up the breaking changes since the last timed release. And in effect, doing the kind of thing that Ember is trying to do now
Starting point is 01:02:24 and that others I would like to see try to do for breaking changes where they just Angular does this, Node does this, lots of things do this. Lean into it. I think Angular and Node could do exactly this.
Starting point is 01:02:38 And instead of saying it's Node 22, you could imagine, especially since they have a six month cadence, that it's Node 24-whatever. I don't remember when the next one comes out. I think September or something. So 24-09. And then the patch and bug fix or patch and feature releases in it.
Starting point is 01:02:58 That could be a really helpful way of distinguishing the marketing dynamics. Hey friends, every time you're out there in the world and you're on public Wi-Fi, let's say a hotel, a cafe, an airport, you're traveling, you're at a friend's house, and maybe they're not very trustworthy. Maybe they are. Who knows? You're not secure. Any hacker on that network can gain access to steal your stuff, take your personal data, and do what they want with it. And it doesn't take much technical knowledge to hack someone. Just some cheap hardware is needed. A Raspberry Pi. I think your data is valuable. And I think hackers think so too because they can make up to $1,000 per person just selling your personal information on the dark web. Could be your phone number. Could be your address.
Starting point is 01:03:55 Could be your driver's license number. Whatever they can get their hands on, they're going to sell it. $1,000 per person? That's crazy. But ExpressVPN stops those hackers from stealing your personal data by creating a secure encrypted tunnel between your device and the internet. And what I appreciate most about ExpressVPN personally is it is super secure. It would take a hacker with a supercomputer over 1 billion years to get past ExpressVPN's encryption. And it's also easy to use. Fire up the app and click one button and you get protected. And that's what I do when I'm in a cafe or an airport or I'm
Starting point is 01:04:33 out there and about. I'm getting my tires changed. I'm gettingvpn.com slash changelog. That's expressvpn.com slash changelog. And you can get an extra three months free. Again, expressvpn.com slash changelog. Let's draw a corollary here, potentially, because arguably Ubuntu has become one of the most popular flavors of Linux to install. A lot of people use it. They were the first to come up with LTS.
Starting point is 01:05:26 They do use, you know, this nomenclature you just mentioned. I just wonder, like, is there a reason potentially beyond the quality of the release cycle, the team behind it, what they've done, et cetera, has their ability to popularize LTSs to be more trustworthy over time, as well as this nomenclature of 2404 or 2204 or 2004, whatever, however it frames out has that. Do you think that's been a corollary to their success? I think there are two values there. One is the clarity in communication, and the other one is the clarity in scheduling, both
Starting point is 01:05:58 internally and externally. So the communication that LTS says, if you use this, you are not on the hook for worrying about security patches. You will get those security patches for predetermined period of time. And so you know what you're signing yourself up for. And being able to credibly make that commitment is valuable. The other half of it is the schedule certainty, both internally and externally. Because I remember some time ago, I was going to build a new computer for myself.
Starting point is 01:06:28 And I looked at the calendar and I was like, oh, what I should do is I should wait for another month because there's going to be a new LTS release out. And so I don't want to set up a brand new Linux install when I'm going to have to go through the whole process again in a month. Right? And knowing that that calendar, you know, is dependable and is going to happen on a predictable cadence is very, very valuable.
Starting point is 01:06:50 I imagine for a large project like that, it's also very valuable internally, because if you're trying to ship a new feature, you don't have to worry about like, will I make it into the next release on time, depending on when that next release is, you know, when the next release is, you know, when the deadline is, it's the same deadline on time, depending on when that next release is. You know when the next release is, you know when the deadline is, it's the same deadline every year, right? And so you know where you stand. You don't have to do any horse trading
Starting point is 01:07:13 with the release manager or PM or whatever, you know, and exchange favors or whatever else needs to happen. I think it eliminates and streamlines a lot of that effort that normally has to happen whenever you're trying to wrangle a big project toward a release. And I think that's useful both for the project itself as well as for people depending on it downstream. At the same time, though, even with your scenario where you want to wait a month because you know the date, at the same time, if you have confidence in the upgradeability from one version to another
Starting point is 01:07:45 like the dot 10 release in particular uh jared you know i've had i've disclosed you behind the scenes some fear like oh my gosh i've got to upgrade my ubuntu i'm going to just i'm going to wipe the system i'm going to back up and i'm start from scratch but i've learned and i've come to you know trust their ability to architect good software to give me an upgrade path. And it's also like, this is probably specific to Linux that as soon as you log in, it lets you know, hey, you've got an upgrade availability, you know, do release whatever it is for the command you run. I've learned to trust that. So at the same time, I might be, well, my, you know, 20, whatever, 21.10 of Ubuntu can easily upgrade to 22.04 safely and I've done it once before and I'll do it again so there you go so I won't wait the month because I have trust
Starting point is 01:08:32 in their ability to release properly but I do think it really comes back to the beginning of the show when you said SemVer is really about communication it's a machine readable way to communicate for both machines and humans that communicates in a lot of ways. And the challenge really is, is like, how well do people adopt it? And are there different permutations of it that misalign or, you know, unalign, I suppose, that makes it challenging to do CIMVR? And like you all said before, if you have to have a PhD in it, is it really worth doing? That's true. But I think, you know, coming out of this conversation,
Starting point is 01:09:07 I'm not thinking Semper needs to die by any means. I'm thinking he needs to live and he needs to have people like you behind it. But it is super challenging. And I think to your point there,
Starting point is 01:09:18 the more that you can make those kinds of transitions seamless, this gets it exactly the kind of thing Pedrag was describing around code mods. Even if you are shipping a breaking change, like even if you don't adopt the slightly more, I'm still mulling on it proposal there of it's not breaking as long as the code mod is good enough. Even if you don't do that, if every breaking change you make, every deprecation you make comes with a good enough code mod so that when you do actually make that breaking change, you could have the kind of confidence that you're talking about, Adam, that you could
Starting point is 01:09:52 know that when I go from React 19 to React 20 or Laravel, whatever the current major is to the next one and so on, that it's going to come with that kind of automation. And that becomes a norm across the ecosystem, or at least for those foundational pieces, I think that would give you a lot more confidence to say, I can take this upgrade that is going to be breaking, but I'm not going to be broken by it because the ecosystem has built this value around this socio-technical contract we've set up with Semver, and we're going to apply all of our technical skill to make the social part of it better. I also think there's a lovely positive feedback loop going on here. We've noticed this.
Starting point is 01:10:38 I think we're all on the same page that releasing your software more often is better than not, right? I'm thinking in the context of, say, like a SaaS application, right? If you release once a year, it's going to be a much more painful release cycle than if you release every week or every day, right? Because big changes are hard to test and small changes are better. I think there's something similar to be said about software and the rate at which you apply upgrades, right? If you accumulate 400 version upgrades
Starting point is 01:11:05 and try to do them all at once, I mean, good luck to you. I just don't want to be anywhere in your blast radius, right? If you try to upgrade them, you know, once a week or even once a day and you have high confidence in the tooling, then good things happen downstream of you. So more good things happen and so on and so on.
Starting point is 01:11:24 The primary method by which Cargo Semver checks, the rust Sanford Linter I built gets adopted is that somebody has an accident, you know, rolls a natural one. And right. I mean, it really is an accident, right? Like they didn't mean to cause a breaking change. It just happens to them. Right. And then they break somebody. And then somebody opens the nation and says, hey, you broke me. This is bad. You need to fix this. And a lot of the time, someone says, oh, by the way, cargo-samver checks catches this. And then no fingers are pointed, no blame is assigned, but you very quickly see that project adopt cargo-samver checks for the next release. And if they adopt cargo- cargo server checks and they ship fewer breaking changes,
Starting point is 01:12:07 then libraries that re-export their API and, you know, rely on it to provide some capabilities downstream, they get broken less often. They might also adopt cargo server checks because they see it works well. And all of a sudden, you know, a rising tide lifts all boats, right? Everyone's software is better off. We can all be updated more often. So we all benefit from the new features faster, we get better performance, we get, you know, security patches patched more promptly and not,
Starting point is 01:12:34 you know, festering open for months while we try to figure out how to navigate our way through all of the changes that we've accumulated, because we haven't updated any piece of software since, you know, right i mean i wish i were making this up but like these are things that happen in the real world right like wasn't there the case that uh a large number of government machines all over the world are still running windows xp right they don't do that because it's fun why do they do it it's very difficult to upgrade okay i wanted to say that's all to be super clear yeah it's hard upgrade so you would you trust the upgrade path it's a little
Starting point is 01:13:11 easier exactly but that comes with maturity too xp was super old right it's important that you not just trust the path but you walk the path regularly right because then you have smaller downstream effects because you have less change every time that you make that change i think that's wisdom hasn't microsoft uh windows been notoriously hard to upgrade every new major version and that been like until maybe more recently has it been less hard whereas like mac os for example which is a popular developer machine has been generally easier to adopt new versions and they made the upgrade path semi-easy i mean for the most part pretty interesting i've had the opposite experience personally really your mileage may vary developer machines might be different i mean if you're installing specialized tools i we feel that too we do audio production so there's times whenever
Starting point is 01:14:00 i literally i think on my main machine i may just recently gotten, I don't even know what the latest version of Mac OS is. So I'm not a great example of it. I usually wait one year to a half a year just to make sure all their kinks are out because Adobe is always behind and Adobe is our suite of production tooling. And so I know there's some level of latency between the two and I just can't risk it because I want to make sure you all sound amazing. Our shows are awesome. They go out on time and I can't be the one that's the just can't risk it because I want to make sure you all sound amazing. Our shows are awesome and they go out on time. And I can't be the one that's the bottleneck on those things
Starting point is 01:14:28 because of my desire to be on the latest Mac OS. So that aside, I do think the upgrade path generally is easier in my experience with Mac OS. I think that actually gets at something really important
Starting point is 01:14:40 that we haven't touched on so far, which is that a concern for backward compatibility, which can make upgrading easier, in this context, the fact that you can still run 16-bit DOS applications on Windows 11, which is amazing in a lot of ways,
Starting point is 01:14:56 also makes it much harder to move the platform forward in other ways. So Apple, by contrast, you want to run an application from the DOS, 16-bit DOS era? Maybe if you're running it in an emulator written in JavaScript, you can do that. Cool.
Starting point is 01:15:13 But on the operating system, absolutely not. On the other hand, that's part of what makes it really easier. I'm not going to say easy because it's an enormously hard task, but easier for Apple to do something like ship an architecture transition from x86 to ARM and pull off the whole thing in a matter of like two and a half years, three years, because a framework that is willing to make breaking changes on the regular can move forward faster, but that's more cost for the people upgrading.
Starting point is 01:15:54 By the same token, somebody who's really committed to backward compatibility can bring along all of the people on their ecosystem very well, but it can often be much harder for them to get the benefits of trying new things. And I think here, actually, the example of React and Ember in the JS ecosystem is a really good example of this, especially it's less true now. React has gotten way more thoughtful about breaking changes, but in that kind of mid-2010s to, you know, like 2018, 2019 time,
Starting point is 01:16:28 React would ship breaking changes much more than Ember would. And React got to try a lot more things than Ember did. On the other hand, I've talked to a lot of senior engineers at very large companies who got stuck on React 16 and never moved on. And that's less true for Ember, but Ember got to try a lot fewer things along the way. There's just a fundamental tension there that then gets manifested in your versioning.
Starting point is 01:16:54 And the versioning is often a symptom rather than the cause in that case. It's telling you a true story, but the story it's telling you might be telling you something else about the dynamics. The fact that Windows can still run DOS 16-bit applications has other consequences for the kind of incoherence of the Windows ecosystem. But that's a really big benefit if you're an enterprise IT administrator who wants to not spend a lot of costs on upgrading applications that just work
Starting point is 01:17:25 for you. Trade-offs all the way down. I also think that good tooling on the part of language developers can massively, you know, tweak whether this problem is insurmountable or not that bad. You know, it's always somewhere on that spectrum, right? Rust has an interesting feature that I really did not appreciate fully when I was starting out, which is that you can have multiple major versions of the same library in your project exist at the same time. And like Chris, you were just saying, this is not a decision that was taken lightly and is not something that is available for free. For one obvious consequence, it makes the version resolver much, much more complicated,
Starting point is 01:18:10 right? Because it now needs to solve a problem that is much bigger in scope. But what that means is that if, you know, Chris, you wrote a library that depends on foo version one, and I wrote a library that depends on foo version two, and now Adam wants to use both of our libraries. So long as our libraries are not something extremely fundamental, like a framework like react that expects to be, you know, in full control of everything going on in the in the environment. Adam can probably just use both of our libraries and be completely fine with the fact
Starting point is 01:18:40 that the two of us can't agree on which version is the correct version of this dependency that Adam doesn't know or care about, right? Now, this is also not for free to Adam, right? It means that when Adam compiles his project, he has to compile two versions of this dependency and not one. So maybe his binary size is a little bit bigger, and maybe there's a little bit of bloat in the development environment and stuff like that, right? But the alternative is Adam having to pick between your library and mine. And I can tell you from the Python 2v3 transition, that is not a pleasant experience to be in. I mean, I lived it. I made good software money, just like moving stuff from Python 2 to Python 3. And if I could have made half as much while dealing with none of that, that might
Starting point is 01:19:25 have been a worthwhile trade. I think that also gets at different languages have to make different trade-offs there. NPM allows that, as do Yarn and PNPM and so on. But you generally are fine with that on the server and extremely not fine with that on the client because your bundle size ends up mattering enormously. And so you have to be able to pick different trade-offs. And the NPM, et cetera, one is hard because it's trying to serve both a server ecosystem and a client ecosystem, a browser ecosystem. And those just have fundamentally different needs. One thing that Rust doesn't do, and NPM theoretically does, and Yarn and PNPM actually do, is support
Starting point is 01:20:07 the idea of peer dependencies, which is this secondary dimension to all of this, where you want to be able to say, I want to support a range of versions of this dependency of mine, and I want to maybe even be able to test against them. And in principle, that's possible in the NPM ecosystem and more or less nowhere else. I think it's an under-invested area. If you're building a new programming language, you should bake peer dependencies in as a first class concept because frameworks, React being the classic example, but in Rust, Tokyo is a very good example similarly. Things that sit at that foundation level that everything else builds on.
Starting point is 01:20:54 You really want to be able to say, my library is currently built against the latest version and Predrogs is built against a version four minor versions back. But both of us just say, we have a peer dependency on the same major. And your resolver can now say, ah, I'm going to get the version that satisfies both of these. And neither of you ships a direct dependency on it. You both specify a peer dependency and that can quote unquote, just work.
Starting point is 01:21:17 And it's a very powerful thing that mostly doesn't exist. Again, Yarn and PNPM finally have gotten this right in about the last two to three years. But it allows you to pick a different set of trade-offs and to bring this all the way back around in very full circle to does Sempra work? It only works because you have that ability to communicate those sets of constraints, that these share the same major version, and they might differ on which features they're using, but they share the same major. And so you can actually build tooling around that. And you can't do that without something shaped like SemVer, even if we iterate on the details along the way.
Starting point is 01:21:59 Well, you answered my unspoken question, which was, is there a better way? And is it too late to unadopt Sunver? Because that was my unspoken question. It's kind of been camping out in that area. It's like, is there a better way? Because it's fraught with a lot of issues and a lot of challenges, but is there a better way? And I think you just kind of answered that. I think the best place to take it from here is to invest in tooling that we have and make it work in even more of the cases starting from scratch we're going to relearn a lot of the same very painful lessons in a much
Starting point is 01:22:31 longer time scale i think right well let's leave folks with some waypoints frederick to some of the tooling you've been building perhaps chris how they can connect with you to plug into this conversation and have uh say because there are so many details and so many little avenues and ways that we can go with this. We could talk about it all day, but we may walk in circles. Semver checks. What'd you call it? Create Semver checks. Cargo Semver checks. Cargo Semver checks.
Starting point is 01:22:59 Seems like maybe state-of-the-art for people who want to build similar tooling for their ecosystem. We have to permeate all ecosystems with this tooling so that everybody who's doing semver can actually do semver as well as we possibly can so maybe that's a great place for people to either help out in rust or look at what you're up to and emulate in their language of choice absolutely and the infrastructure that cargo semver checks is built on the core piece is called trustful. It is a weird take on a database query engine that is a topic for a whole other podcast episode sometime. Okay. But the key thing there is that it's language agnostic. So it has bindings
Starting point is 01:23:39 for Python, it works in JavaScript, you can, you know, you can run it in WASM in the web browser, if you wanted to, you could call it from anything. And so you could use it as the foundation of a Semver Linter for another language. That's, in fact, how my Python Semver Linter works as well. And I'm trying to talk Chris into building one for TypeScript. I already have too many projects. But if somebody else wants to partner with us on it... There you go.
Starting point is 01:24:04 Then what? Then reach out. us on it. There you go. Then what? Then reach out. Then reach out. Okay. Yeah. So on my end. Predrog, I'll let you finish and then I'll. Yeah.
Starting point is 01:24:14 And Cargo Sanford Checks and TrustFall are both completely open source. So if someone wants to come in, learn how to write some lints, check out a weird database, maybe write some database optimizations or, you know, whatever you're interested in. Very happy to do that. Like I mentioned earlier, I worked with four college students who did some tremendous work and honestly made cargo server checks into what it is today. So if four people who hadn't even finished college yet could have such a spectacular impact on the ecosystem, then anyone listening to this podcast could absolutely have a huge impact. So come talk to me.
Starting point is 01:24:51 I'm very happy to help. Yeah. On my end, I will say if you're in the TypeScript community, do look at semvert.org, semver-ts. dash TS. The other thing is I'm happy to help someone get up to speed on how you would translate that spec, which it's very long and very detailed because it has to be, how you would translate that into a query rule set for something like TrustFall, because I do think we could do it. And I think we could do it using a lot of existing infrastructure like TypeScript ESLint. I don't think it would be a boil the ocean from scratch project. But the other thing I'll say is if you want to think about, hey, how would we do this for Elixir, especially as Elixir starts pulling in types and makes a lot of these things even more tractable than it would already be
Starting point is 01:25:40 today, I'd be very happy to talk to you about what a semver-elixir.org kind of spec might look like. And I would actually love to see these kinds of things emerge more generally of what is it you need to think about. Cargo has a 10,000 word document, which you can read through and gets added to on the regular. TypeScript now has one, though I'm basically the only maintainer. I would love other people to contribute there. And if we started building up that kind of ecosystem of projects for a variety of languages, what does it look like in C Sharp? What does it look like in Java? And started making that more of a norm. What does it look like in Ruby? That can also get a flywheel going because someone doing the time to think
Starting point is 01:26:21 through that, and then a bunch of other people taking the time to codify that into something like the TrustFall rules engine, build a schema, and ship those kinds of things. We could make this a norm that is, maybe we're having a conversation five years from now where tons of languages do this and it's just normal. That would be amazing. And it's just time and effort. And that's a big just on that statement. But it is a just. These things are actually tractable, solvable problems. So come talk to me.
Starting point is 01:26:52 You can find me at chriscrycho.com and email and whatnot is all there. I'm on. I'm really easy. I'm at chriscrycho everywhere because it's a globally unique identifier. There's only one of me on the planet. Is that right? Good for you. Easy to find. My blog is Predrog because
Starting point is 01:27:09 .ag is a TLD and it's an uncommon enough name. He's a TLD hacker. It's just Predrog. You guys make sure we get links to all of those things. I got Hiram's Law. We have some other stuff that we'll throw into the show notes so everybody can just click through
Starting point is 01:27:27 versus having to type and memorize and whatnot. Very cool. Adam, anything else? My thought after this conversation is that there should be some sort of consortium or working group or just collective for Simver. People who care. Right.
Starting point is 01:27:40 Because you've got skin in the game, you do care, and you've got expertise that applies. And so just as you said, if you want to help somebody else in a different ecosystem, you're willing to help them out. I feel like there needs to be like a little group of you, you all folks, who just care enough to cross-pollinate so that the whole entire ecosystem of software gets better because it's not about camps. That's why this show is called The Change Law, and not The Rush Show or The Ruby Show or the whatever show, because we cared more importantly about software at large, the intersection of software and business, and all the fun things you know about this show. That's why we went that route, because we cared about software at large,
Starting point is 01:28:14 open source at large, and just really the direction we can all go, the culture of software development. And so I would encourage you guys to consider, if it doesn't exist, make it exist. And if you do... Semver Nerds. Yeah, Semver Nerds. There you go. I like make it exist and if you do simver nerds yeah simver nerds there you go i like that jared come join the simver nerds community is there a dot nerds tld because then we could have simver dot nerds that would be there needs to be there
Starting point is 01:28:33 should be a predator go figure something out awesome thanks guys yeah thank you so much it's been awesome my pleasure yeah thanks for having us. Thanks for having us. Thank you for having us. Okay. Semver nerds unite. It is time to communicate better software through versioning. And I'm, I've changed my mind during this podcast. I came into the show and maybe you can tell because I was kind of against Semver.
Starting point is 01:29:00 It's kind of hard to understand. It's generally been problematic for me. Others may have different experience, but after hearing Predrog and Chris's arguments and their stances and their experiences and their passion, really, and more so their expertise in Simver, I'm thankful they're on the front lines for one. And number two, I'm kind of for it. It does communicate. It has a place and we just need to keep working to improve it, working to adopt it and working to better help folks understand exactly what Semver is, where its place is and how to use it. What do you think? Come hang with us in Slack, changelog.com slash community. Free to join. By the way, this show has a bonus for our Plus Plus subscribers. Head to changelog.com slash plus plus. It's better. Yeah, it's better. ChangeLog++ is better. Drop the ads, get a sticker pack, bonus content, closer to the metal, all the fun things you get
Starting point is 01:30:00 when you directly support us through ChangeLog plus plus once again changelog.com slash plus plus okay a massive thank you to my new friends over at retool well i say new friends because i made some new friends i went a couple layers deeper i talked to david shu the founder and ceo i talked to tamar ben sharkar on behalf of neon recently and CEO. I talked to Tamar Ben-Sharkar on behalf of Neon recently. And I've been talking to Daniel Kim behind the scenes, making all that happen. It's so fun to work with partners and sponsors like Retool. And they're awesome. Check them out, retool.com.
Starting point is 01:30:36 And, of course, to our good friend Firas Aboukdijeh, representing Socket. Socket.dev. Ship faster, secure your dependencies. Check them out, socket.dev ship faster security dependencies check them out socket.dev and also to our partners over at fly that's the home of changelog.com we love them you should love them too check them out fly.io and to the beat freak in residence break master cylinder those beats so bang it so bang it okay plus plus subscribers stick around everyone else we'll see you on friday frederick you wrote one of my favorite blog posts of the year you wrote it on april fool's day it
Starting point is 01:31:19 was not a trick it actually happened this was the the Wi-Fi only works when it's raining. And I didn't know you then. I know you now. I'm happy to know you. I shared it on Change Dog News because I love this little story. Share it with Adam. I'm not sure if Adam saw this. Chris, you're nodding along. So you know this story pretty well. This is just a hilarious fact
Starting point is 01:31:40 of life in the common, in the modern world. Can you tell that story just briefly for our plus plus people? Absolutely. So it's a completely true story. It was part of a project called April Cools that a friend of mine started. We decided that it was a little bit tacky to lie to people on April 1st and instead decided to pleasantly surprise people with true stories that are on topics unrelated
Starting point is 01:32:03 to our usual beat. Okay.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.