[HN Gopher] Deprecate like you mean it
       ___________________________________________________________________
        
       Deprecate like you mean it
        
       Author : todsacerdoti
       Score  : 47 points
       Date   : 2025-12-11 15:52 UTC (7 hours ago)
        
 (HTM) web link (entropicthoughts.com)
 (TXT) w3m dump (entropicthoughts.com)
        
       | WhyOhWhyQ wrote:
       | Another idea is to make the deprecation warning increasingly
       | scary sounding.
        
         | GuinansEyebrows wrote:
         | "DEPRECATED: i will literally kill you"
        
           | WhyOhWhyQ wrote:
           | "Continuing to use this feature is a moral failure on your
           | part and you should be ashamed, your parents should be
           | ashamed, and dishonor will follow you wherever you go."
        
             | s1mplicissimus wrote:
             | "If you don't migrate I will tell your mum"
        
             | GuinansEyebrows wrote:
             | sorry, i'm not afraid of this. i'll keep using the feature.
        
       | xahrepap wrote:
       | > That would probably not trigger anyone's midnight pager, but it
       | would make it clear that relying on the deprecated functionality
       | is a bug lurking in the code.
       | 
       | How do you know? This is a wild assertion. This idea is terrible.
       | I thought it was common knowledge that difficult to reproduce,
       | seemingly random bugs are much more difficult to find and fix
       | than compiler errors.
       | 
       | If you're ready to break your api, break your api. Don't play
       | games with me. If more people actually removed deprecated APIs in
       | a timely manner, then people will start taking it more seriously.
        
         | pavel_lishin wrote:
         | Yeah, I agree - this sort of intermittent failure could be
         | incredibly hard to track down, and will absolutely fuck with
         | people's faith in their CI systems as well - a flappy test is
         | the absolute worst kind of test.
        
         | matthewkayin wrote:
         | I agree, maintainers should just break the API if they're going
         | to do it.
         | 
         | At the same time, it's crazy that urllib (the library mentioned
         | in the article), broke their API on a minor version. Python
         | packaging documentation[1] provides the sensible guideline that
         | API breaks should be on major versions.
         | 
         | [1]
         | https://packaging.python.org/en/latest/discussions/versionin...
        
         | Certhas wrote:
         | Last paragraph of the article:
         | 
         | > In case the sarcasm isn't clear, it's better to leave the
         | warts. But it is also worthwhile to recognise that in terms of
         | effectiveness for driving system change, signage and warnings
         | are on the bottom of the tier list. We should not be surprised
         | when they don't work.
        
           | layer8 wrote:
           | Most HN visitors won't read to the last paragraph, so it's a
           | good thing to emphasize.
        
             | xahrepap wrote:
             | I thought I had read it. :) I thought the three `* * *` at
             | the bottom was indicating I was about to start reading
             | suggestions for the next article. So definitely a "Woosh"
             | moment for me :D
        
           | xahrepap wrote:
           | Yeah, totally a woosh moment for me. Read all the way up to
           | the `* * *`. That's on me :)
        
       | dec0dedab0de wrote:
       | Please do the opposite. Let all deprecation warnings last at
       | least a decade, just include in the warning that it is not
       | maintained.
       | 
       | But more to the point, go out of your way to avoid breaking
       | backwards compatibility. If it's possible to achieve the same
       | functionality a different way, just modify the deprecated
       | function to use the new function in the background.
       | 
       | My biggest problem with the whole static typing trend is that it
       | makes developers feel empowered to break backwards compatibility
       | when it would be trivial to keep things working.
       | 
       | edit: Not that it is always trivial to avoid breaking backwards
       | compatibility, but there are so many times that it would be.
        
         | jkubicek wrote:
         | > just include in the warning that it is not maintained.
         | 
         | I'm convinced this isn't possible in practice. It doesn't
         | matter how often you declare that something isn't maintained,
         | the second it causes an issue with a [bigger|more
         | important|business critical] team it suddenly needs become
         | maintained again.
        
           | tux3 wrote:
           | And here's where your business can contact me to talk about a
           | support contract.
           | 
           | If it's important, they'll pay. Often you find out it wasn't
           | that important, and they're happy to figure it out.
        
             | nisegami wrote:
             | It sounds like you're imagining open source whereas the
             | comment you're replying to is imagining more intra-company
             | dependencies.
        
               | mbreese wrote:
               | I think deprecation in intra-company code is a completely
               | different beast. You either have a business case for the
               | code or not. And if something is deprecated and a
               | downstream project needs it, it should probably have the
               | budget to support it (or code around the deprecation).
               | 
               | In many ways, the decision is easier because it should be
               | based on a business use case or budget reason.
        
               | zamadatix wrote:
               | The business case is the easy part, the quagmire is in
               | getting the different teams to agree who should support
               | the business case, why it's more important than the
               | business cases they wanted to spend cycles on instead,
               | and how much of the pie supporting it takes on the budget
               | side. Less so when the place is small enough everyone
               | knows everyone's name, more so when it's large enough
               | they really don't care what your business case is much
               | even though it'd be 10x easier to support from their side
               | instead of another.
        
               | spockz wrote:
               | Oh. But that is a solved problem. The users of the
               | library just copy the code from before the deprecation
               | and then stick it in their codebase not to be maintained
               | anymore. Problem solved. /s
        
           | taeric wrote:
           | I don't know that I see why/how this is a problem? You would
           | do the same with any other thing in your life?
           | 
           | More, in many things, we have actively decided not to do
           | something anymore, and also highly suggest people not mess
           | with older things that did use it. See asbestos. Removing it
           | from a building is not cheap and can be very dangerous.
        
           | dietr1ch wrote:
           | It also keeps slowing down development as getting a green
           | global compile will make you still update "deprecated"
           | functions that face breaking API changes.
        
         | ryandrake wrote:
         | One thing I've always hated was this idea of "bitrot." That
         | software just spontaneously stops working after time and loses
         | backwards compatibility. Like it's some force of nature.
         | 
         | It's not a force of nature. Bitrot is: many software developers
         | deliberately choosing to break backward compatibility in very
         | small ways over and over. Software written in 1995 _should_
         | still work today. It 's digital. It doesn't rot or fall apart.
         | It doesn't degrade. The reason it doesn't work today is
         | _decisions_ that platforms and library maintainers deliberately
         | made. Like OP. Deprecate like you mean it. That 's a choice!
         | 
         | If we want to solve bitrot, we need to stop making that choice.
        
           | jcalvinowens wrote:
           | Progress is often only possible by breaking things. It's not
           | a choice, it's the only way forward. We have to optimize for
           | the future being better, even if it makes the present a
           | little worse occasionally.
           | 
           | This is a huge reason why open source projects are often so
           | much more successful than corporate clones: they actually
           | iterate and innovate, something corporate america has
           | forgotten how to do.
        
             | mxey wrote:
             | Actually this is the reason why Win32 is the stable ABI for
             | Linux.
             | 
             | https://blog.hiler.eu/win32-the-only-stable-abi/
        
               | jcalvinowens wrote:
               | While I certainly empathize with the author of that
               | article and respect the work they put into debugging it,
               | this is a better explanation of that whole thing:
               | https://maskray.me/blog/2022-08-21-glibc-and-dt-gnu-hash
        
             | ryandrake wrote:
             | It's absolutely a choice. _All_ software can progress while
             | preserving backward compatibility for existing users. It 's
             | not always easy, but it's never impossible.
        
               | jcalvinowens wrote:
               | > All software can progress while preserving backward
               | compatibility for existing users
               | 
               | That's an _incredibly_ ignorant claim. Just run  "git
               | log" in glibc, it won't take you very long to prove
               | yourself wrong.
        
               | mxey wrote:
               | glibc, which has had ABI compatibility for decades?
        
               | jcalvinowens wrote:
               | There have been _plenty_ of build breaking changes over
               | the past couple decades, generally they happen for very
               | good reasons and only affect niche usecases.
        
               | mxey wrote:
               | So existing binaries will keep working?
        
               | jcalvinowens wrote:
               | Not necessarily if you go back far enough to have nss
               | problems :)
        
             | cortesoft wrote:
             | Some deprecations are required to make progress. Many
             | others aren't, and those are the most frustrating.
             | 
             | For example, ruby deprecated the `File.exists?`, and
             | changed it to `File.exist?`, because enough people felt
             | that the version with the `s` didn't make sense
             | grammatically (which I disagree with, but that is not
             | germane to my point).
             | 
             | For a long time, you would get warning that `exists?` was
             | deprecated and should be replaced by `exist?`.... but why?
             | Why couldn't they just leave `exists?` as an alias to
             | `exist?`? There was not cost, the functions are literally
             | identical except for one letter. While the change was
             | trivial to fix, it added annoyance for no reason.
             | 
             | Although, luckily for me, with Ruby I can just make exists?
             | an alias myself, but why make me do that?!? What is the
             | point of removing the method that has been there forever
             | just because you think the s is wrong?
        
               | jcalvinowens wrote:
               | Your example could be fixed in your entire codebase with
               | a single sed invocation. While yes, if it were up to me
               | I'd probably just have left the alias, the annoyance for
               | the end user does seem quite minimal...
               | 
               | You get to use open source projects _for free_ , and a
               | lot of people do ongoing maintenance on them which you
               | benefit from _for free_. In return, sometimes you are
               | expected to modify your code which depends on those
               | projects because it makes their maintainer 's life
               | easier.
               | 
               | Personally, I see that as a very reasonable trade-off.
        
               | Ferret7446 wrote:
               | The third option is to use things that don't break
               | themselves. One of the many joys of Go is that I can
               | leave personal projects untouched for years and then go
               | back and everything is still working
        
               | bigstrat2003 wrote:
               | You've moved the goal posts quite a bit from your
               | previous post to this one. Originally, you said that
               | "progress is often only possible by breaking things...
               | it's the only way forward". But the Ruby example that
               | cortesoft provided isn't necessary to make progress. The
               | language would get by just fine without that deprecation
               | (or even without making the change at all). Saying "but
               | it's a trivial change" in response is irrelevant, because
               | you weren't originally trying to justify changes on the
               | basis that they were easy, but that they were necessary.
        
               | jcalvinowens wrote:
               | > Saying "but it's a trivial change" in response is
               | irrelevant
               | 
               | Of course it's relevant. It's a laughably trivial example
               | compared to the other one in this thread.
        
               | cortesoft wrote:
               | > Your example could be fixed in your entire codebase
               | with a single sed invocation
               | 
               | I also have to hope all the dependencies I use did that,
               | too.
               | 
               | But my real question is why? Why make me do it at all?
        
               | jcalvinowens wrote:
               | Because they wanted to, and it's their project. Part of
               | being an adult is accepting you won't agree with every
               | decision that affects you.
               | 
               | You were free to show up and argue against it, as was
               | anyone else. Did you?
        
               | coryrc wrote:
               | Imagine I am new to Ruby. I go looking to figure out if a
               | file exists. Or I get a list of available methods from
               | the file object. Now I have to research both `exist?` and
               | `exists?` to figure out if I should be choosing one or
               | the other.
               | 
               | Now multiply that by.... every past history of every API
               | and it makes adopting something really difficult as a
               | newcomer.
               | 
               | aka Common Lisp.
        
               | jcalvinowens wrote:
               | I'm not defending the Ruby decision, I literally said I
               | wouldn't have done it. It reminds me of the disttools
               | removal from python, which was also not something I'd
               | have done nearly so aggressively if it were up to me.
               | Multiple distros have patched it back in.
               | 
               | But it wasn't up to me. It's not my project. I'm using
               | _somebody else 's project_, and at the end of the day
               | it's _their_ decision, because _they_ own it. Unless it
               | 's impossible to work around, I feel like I have to
               | either respect that, or switch to an alternative.
               | 
               | You're free to maintain a patch on top of Ruby to add the
               | alias and run that on your machines, btw. It would
               | probably be very simple, although certainly not as simple
               | as aforementioned sed command...
        
           | shadowgovt wrote:
           | God, would I hate to be programming now the way I had to
           | program in 1995.
           | 
           | Granted, modern coroutines do bring up some nostalgic feel
           | for the days I had to support cooperative multitasking...
        
         | mxey wrote:
         | > Not that it is always trivial to avoid breaking backwards
         | compatibility, but there are so many times that it would be.
         | 
         | In this case it was 2 functions with 1 line of code each.
         | https://github.com/urllib3/urllib3/pull/3732/files
        
           | Spivak wrote:
           | Wow. Why even remove it? It's just the thinnest wrapper
           | around the dict and since the dict is now part of the public
           | API these methods will work forever unmodified.
        
         | shadowgovt wrote:
         | As with all things, this can be pushed too far. Microsoft was
         | suffering a maintainability crisis before the transition to
         | Windows XP; their years of bending the API to support customers
         | (which, in the short run, did keep customers to their benefit)
         | was making for a fairly unmaintainable mess of an API surface
         | that then screamed under the strain when the Internet era hit
         | and all those open, under-observed APIs became potential worm
         | attack vectors.
        
           | Wowfunhappy wrote:
           | Actually, I think backwards compatibility is the reason
           | Windows still dominates. It isn't the best OS at anything and
           | it's actively user hostile, but if you want to run Windows
           | apps... there are decades of Windows apps and they basically
           | all work.
        
         | zahlman wrote:
         | > My biggest problem with the whole static typing trend is that
         | it makes developers feel empowered to break backwards
         | compatibility when it would be trivial to keep things working.
         | 
         | I don't see the connection you're drawing here.
        
           | ljm wrote:
           | Rather, static typing empowers backwards compatibility,
           | right?
           | 
           | Because it lays out the contract you have to meet on the
           | interface. No contract? No enforced compatibility.
        
             | dec0dedab0de wrote:
             | It is a way to signal to other developers that your code
             | changed, which is better than not saying anything.
             | 
             | But it seems to make library developers more comfortable
             | with making breaking changes. It's like they're thinking
             | 'well it's documented, they can just change their code when
             | they update and get errors in their type checker/linter.'
             | When I think they should be thinking, 'I wonder what I
             | could do to make this update as silent and easy as
             | possible.'
             | 
             | Of course, we all have different goals, and I'm grateful to
             | have access to so many quality libraries for free. It's
             | just annoying to have to spend time making changes to
             | accommodate the aesthetic value of someone else's code.
        
               | ljm wrote:
               | I think the only time I've ever seen this is in a JS
               | library, where each major version bump is practically a
               | different library altogether because it's a complete
               | rewrite, and these days is a wrapper around some Rust
               | thing.
               | 
               | Not even JS alone. I blame the enforcement of semantic
               | versioning, as if a version of code simply had to be a
               | sequence of meaningful numbers.
        
               | thayne wrote:
               | But it also makes it easier for library developers to
               | identify that a change is breaking. Without static types
               | you can easily make a change you think is fine, but it
               | ends up breaking user code because they depended on
               | something you didn't expect. Granted, static typing
               | doesn't completely solve that problem, there can still be
               | changes in behavior that break things, but it is a useful
               | tool in identifying certain classes of breaking changes.
        
           | eyelidlessness wrote:
           | Disclaimer: I'm a strong advocate for static typing.
           | 
           | I absolutely see the connection. One of the advantages of
           | static typing is that it makes a lot of refactoring trivial
           | (or much more than it would be otherwise). One of the side
           | effects of making anything more trivial is that people will
           | be more inclined to do it, without thinking as much about the
           | consequences. It shouldn't be a surprise that, absent other
           | safeguards to discourage it, people will translate trivial
           | refactoring into unexpected breaking changes.
           | 
           | Moreover, they may do this consciously, on the basis that "it
           | was trivial for me to refactor, it should be trivial to adapt
           | downstream." I'll even admit to making exactly that judgment
           | call, in exactly those terms. Granted I'm much less cavalier
           | about it when the breaking changes affect people I don't
           | interface with on a regular basis. But I'm much less cavalier
           | about that sort of impact _across the board_ than I've
           | observed in many of my peers.
        
           | layer8 wrote:
           | I could see some maintainers being encouraged by static
           | typing to introduce breaking changes, as long as the changes
           | ensure compile-time breakage. However, that's only an option
           | in languages without dynamic linking. So it's the combination
           | of static typing and static linking that would encourage
           | that.
        
         | socalgal2 wrote:
         | I was hoping to spin it as an environmental concern. You change
         | something "for reasons". If you're doing this in a popular
         | tool/library you probably just burnt down a small forest of
         | trees worth of energy from all of the work people will have to
         | put in deal with it. 100s of thousands of users missed dinner
         | with a kid or loved one because of the extra work you created.
         | A product that would of shipped on time didn't. Things you
         | wanted to exist didn't because 100k people were distracted
         | dealing with your breakage.
        
       | syntheticnature wrote:
       | Wow, tell me you've never shipped anything important / heavily
       | used without telling me that.
       | 
       | I expected this to suggest a tick-tock deprecation cycle, where
       | one version deprecated and the next removed, but this is
       | definitely an idea that belongs on the domain
       | "entropicthoughts.com"
        
       | fwip wrote:
       | Profoundly awful idea.
        
       | s1mplicissimus wrote:
       | I get that it's nice to be able to deprecate/remove things.
       | 
       | But intentionally breaking my users runtime in a way that's
       | really hard and annoying to find? Is the author OK? This reads
       | like a madman to me.
        
       | YetAnotherNick wrote:
       | Instead randomly trigger kill self process. That's a safer way
       | than random wrong returns.
        
       | Pingk wrote:
       | This isn't a good idea regardless of why it's being deprecated.
       | 
       | If it's no longer being maintained then put a depreciation
       | warning and let it break on its own. Changing a deprecated
       | feature just means you _could_ maintain it but don 't want to.
       | 
       | Alternatively if you want to aggressively push people to migrate
       | to the new version, have a clear development roadmap and force a
       | hard error at the end of the depreciation window so you know in
       | advance how long you can expect it to work and can document your
       | code accordingly.
       | 
       | This wishy-washy half-broken behaviour doesn't help anyone
        
       | cowsandmilk wrote:
       | Please don't do this. If you want to remove the function, remove
       | it and insist on its removal when people complain. Don't
       | gradually break people.
        
       | HarHarVeryFunny wrote:
       | Having a deprecated API just randomly return failures is an awful
       | idea!
       | 
       | Better to give an actual timeline (future version & date) for
       | when deprecated functionality / functions will be removed, and in
       | the meantime, if the language supports it, mark those functions
       | as deprecated (e.g. C++ [[deprecated]] attribute) so that
       | developers see compilation warnings if they failed to read the
       | release notes.
        
         | psygn89 wrote:
         | Yep. I'll admit I've acted faster to hard set dates than some
         | "in the future" message. I've also seen some tools become
         | really noisy about deprecation spanning many lines AND
         | repeating. Please don't log the same message over and over for
         | each instance. Color or add emoji if you must to grab
         | attention, but once is enough. It's annoying when you can't do
         | anything about it at that time and have to sift through this
         | extra noise when hunting down another issue in the CI log. Add
         | a link that goes over it in more detail and how to migrate for
         | that specific deprecation.
        
         | cortesoft wrote:
         | I don't think that was a serious suggestion, the article says
         | it is sarcasm near the end.
         | 
         | But yes, that would be the worst idea ever.
        
         | coryrc wrote:
         | Random is bad, but scheduled windows of breakage is good.
        
       | pron wrote:
       | Occasionally returning wrong results is irresponsible, of course,
       | but how about making deprecated APIs grow gradually _slower_?
        
       | kibwen wrote:
       | Don't make it return a different result.
       | 
       | Instead, if you must, add a sleep within the function for 1 ms in
       | the first release, 2 ms in the second release, and so on. But
       | maybe just fix the tooling instead to make deprecations actually
       | visible.
        
         | helle253 wrote:
         | this actually seems like an reasonable technical solution to
         | the non-technical problem that causes deprecations to be
         | ignored in the first place
         | 
         | Degrading performance exponentially (1ms, 2ms, 4ms, 8ms...)
         | WILL create a 'business need', without directly breaking
         | critical functions. Without this degradation, there is no
         | reason to remove the deprecated code, from a business
         | perspective.
        
           | newAccount2025 wrote:
           | It should slow down your compile instead of the runtime. That
           | way the pain is felt by the developer who can fix it.
        
         | shadowgovt wrote:
         | It is sometimes a tooling issue, but far more often it's a "few
         | teams have a discipline of squashing all toolchain warnings"
         | issue.
        
         | csydas wrote:
         | I get the intention but it's a bad idea, same with the article
         | 
         | if people are meant to depend on your endpoints, they need to
         | be able to depend on all of them
         | 
         | you will always have ppl who don't respond to deprecation
         | notices, the best you can do is give them reliable information
         | on what to expect -- if they hide the warnings and forget,
         | that's their business
         | 
         | but intentionally making problems without indication that its
         | intentional results in everyone (including your own team) being
         | frustrated and doing more work
         | 
         | you cannot force ppl to update their code and trying to agitate
         | them into doing it only serves to erode confidence in the
         | product, it doesn't make the point ppl think it makes, even if
         | the court of public opinion sides with you
         | 
         | cover your bases and make a good faith effort to notify and
         | then deal with the inevitable commentary, there will always be
         | some who miss the call to update
        
       | mac3n wrote:
       | sure - because i rewrite all my code every year!
        
       | 1313ed01 wrote:
       | No. Breaking other people's code is why we have this broken
       | software world where new bugs (and security holes) are added
       | everywhere all the time since no software is allowed to just
       | exist without monthly rewrites. We need a culture where breaking
       | backwards compatibility in published APIs is almost unthinkable,
       | not something anyone would want to be caught doing.
        
       | froh42 wrote:
       | I had the same clever idea once. Deprecation warning, and it
       | would (by the power of a C-Macro) auto-turn off when the relase x
       | was reached, with louder and louder warnings before.
       | 
       | One day I came back from holidays. I had just broken a big go-
       | live where the release number passed x. Date missed, next
       | possibility in a few weeks. The team was pissed.
       | 
       | Yes they COULD have fixed the warnings. But breaking the go live
       | was quite of of proportion for not doing so.
        
         | zahlman wrote:
         | Could the clients have reasonably foreseen when the release x
         | would occur?
         | 
         | Could they not have rolled back?
        
       | xd1936 wrote:
       | Chaotic Evil code.
        
       | oivey wrote:
       | It would help a lot if core Python libraries like urllib, NumPy,
       | and others used SemVer. Removing a function is a breaking change.
       | The root of this post is from urllib breaking something in a
       | minor release. Get rid of the pseudo SemVer where you can
       | deprecate functions and then break in minor releases. Maybe after
       | that the rest of the community could hope their code will work
       | long term if they don't increment major versions.
        
         | graemep wrote:
         | Python itself is making breaking changes between minor
         | versions, so I think its natural that the ecosystem will
         | follow.
         | 
         | I have not had any real problems yet myself, but its worrying.
        
           | zahlman wrote:
           | Python has never claimed to use semver, despite everyone
           | associating the 3 in front with the 2->3 migration.
        
         | kerkeslager wrote:
         | > Get rid of the pseudo SemVer where you can deprecate
         | functions and then break in minor releases.
         | 
         | I agree, but I think there's a bigger, cultural root cause
         | here. This is the result of toxicity in the community.
         | 
         | The Python 2 to 3 transition was done properly, with real
         | SemVer, and real tools to aid the transition. For a few years
         | about 25% of my work as a Python dev was transitioning projects
         | from 2 to 3. No project took more than 2 weeks (less than 40
         | hours of actual work), and most took a day.
         | 
         | And unfortunately, the Python team received a _ton_ of hate
         | (including threats) for it. As a natural reaction, it seems
         | that they have a bit of PTSD, and since 3.0 they 've been
         | trying to trickle in the breaking changes instead of holding
         | them for a 4.0 release.
         | 
         | I don't blame them--it's definitely a worse experience for
         | Python users, but it's probably a better experience for the
         | people working on Python to have the hate and threats trickle
         | in at a manageable rate. I think the solution is for people
         | like us who understand that breaking changes are necessary to
         | pile love on doing it with real SemVer, and try to balance out
         | the hate with support and
         | 
         | I had a client who in 2023 still was on 2.7.x, and when I found
         | a few _huge_ security holes in their code and told them I
         | couldn 't ethically continue to work on their product if they
         | wouldn't upgrade Python, Django, and a few other packages, and
         | they declined to renew my contract. As far as I know, they're
         | still on 2.7.x. :shrug:
        
         | Hizonner wrote:
         | That just encourages people to keep using old, unmaintained,
         | insecure versions of libraries. Then, when they're still on
         | version 2.1.1, and your maintained version is 5.7.3, and
         | somebody finds a major security bug in 2.1, they will come
         | whining at you to release a 2.1.2.
         | 
         | Code that is not being maintained is not usually suitable for
         | use, period.
        
           | patmorgan23 wrote:
           | And then you can offer them a support contract to produce an
           | update for an out of support version
        
         | zahlman wrote:
         | Numpy does use semver.
         | 
         | Lots of people still complained about 2.0.
        
       | taeric wrote:
       | This is silly and ignores how things are "deprecated" in every
       | other practice on earth. Do we still install knob and tube
       | electricity? Absolutely not. Is there still some out there that
       | somebody is supporting some? Of course.
       | 
       | Does this mean that people and places shouldn't migrate out of
       | older practices? No. But people have different priorities. And
       | sure, we may treat "squeaky wheel policies" as a bad idea, but
       | quite frankly that is far and away the most common policy out
       | there.
       | 
       | To that end, please don't go out of your way to insist that your
       | priority is everyone else's priority.
        
       | wombatpm wrote:
       | How are you supposed to deal with recalcitrant users? I work for
       | an organization that is ending support for several long running
       | APIs. And by support I mean turn off the servers, you must move
       | to an entirely new platform.
       | 
       | We've sent out industry alerts, updated documentation and emailed
       | all user. The problem is the contact information goes stale. The
       | developer who initially registered and set up the keys, has moved
       | on. The service has been running in production for years without
       | problems and we've maintained backwards compatibility.
       | 
       | So do we just turn it off? We've put messages in the responses.
       | But if it's got 200ok we know no one is looking at those. We've
       | discussed doing brownouts where we fail everything for an hour
       | with clear error messages as to what is happening.
       | 
       | Is there a better approach? I can't imagine returning wrong data
       | on purpose randomly. That seems insane.
        
         | ryandrake wrote:
         | Step 1: Stop thinking of them as "recalcitrant". They're not
         | recalcitrant. They bought (presumably for money) a product, and
         | expect that product to keep working as long as they need it to!
         | They don't expect the vendor to pull the rug out from under
         | them and break it just because the API is old and icky and
         | their software engineers are sad to keep it around.
         | 
         | Instead of "deprecate like you mean it" the article _should_
         | be:  "Release software like you mean it" and by that, I mean:
         | Be serious. Be really, really sure that you are good with your
         | API because users are going to want to use it for a lot longer
         | than you might think.
        
           | tormeh wrote:
           | Software evolves over time, along with business needs. What
           | seemed like (or even was!) a good idea at some point will
           | almost surely cease to be a good idea at some point in the
           | future. Breaking the API is totally fine if there's a good
           | reason and it's carefully managed.
        
           | kerkeslager wrote:
           | I agree, get the API right as much as possible so it doesn't
           | need to be deprecated.
           | 
           | But, perfection isn't realistic. If you don't have a plan for
           | when you get things wrong, you're failing to plan for the
           | inevitable.
        
           | Archelaos wrote:
           | > They bought (presumably for money) a product, and expect
           | that product to keep working as long as they need it to!
           | 
           | This depents on the terms of the contract. Typically,
           | termination of service is covered in a license. If the
           | license terms are okay in the respective jurisdiction, there
           | is no fundamental ethical obligation to run a server beyond
           | that. There might exist specific cases where it would be
           | inappropriate to follow the terms by the letter, but that
           | also has its limits.
        
             | ryandrake wrote:
             | Contract terms usually define legal obligations, not
             | ethical obligations. They create duties parties must
             | perform or face legal consequences--they don't speak to
             | what those parties _should_ do ethically.
        
               | Archelaos wrote:
               | Following legal obligations is an important part of
               | ethics. The law has also the purpose to relieving the
               | individual of the burden of complex ethical
               | considerations. This is the general situation, especially
               | in a democracy under the rule of law.
               | 
               | There are, of course, exceptions and disagreement about
               | specific regulations. But as long as you have the law on
               | your side is a very strong indicator that what you are
               | doing is also ethical more or less okay. It is very hard
               | to say that one person is far off ethically, if two
               | people agreed on something and the terms of their
               | agreement are without doubt legally correct.
        
               | ryandrake wrote:
               | I appreciate your viewpoint, even though mine is the
               | exact opposite!
        
           | eddd-ddde wrote:
           | Nothing lasts forever. The second you decide to use a new 3P
           | API you have to understand it might disappear one hour after
           | your production launch, and that's okay.
        
         | GuB-42 wrote:
         | > How are you supposed to deal with recalcitrant users?
         | 
         | Keep the servers running, but make the recalcitrant users pay
         | for the costs and a then some more. It is actually a common
         | strategy. Big, slow companies often have trouble with
         | deprecation, but they also have deep pockets, and they will
         | gladly pay a premium so that they can keep the API stable at
         | least for some time.
         | 
         | If you ask for money, you will probably get more reactions too.
        
         | tormeh wrote:
         | Sleep()s that increase exponentially every month seem like a
         | good solution. When the API has a 10 second latency hopefully
         | someone starts asking questions. If not I think brownouts are a
         | decent idea.
        
         | kerkeslager wrote:
         | A technique I used on a project was to change the URL, and have
         | the old URL return a 426 with an explanation, a new link, and a
         | clear date when the moved API. This reliably breaks the API for
         | clients so that they can't ignore it, while giving them an easy
         | temporary fix.
         | 
         | Clients weren't happy, but ultimately they did all upgrade. Our
         | last-to-upgrade client even paid us to keep the API open for
         | them past the date we set--they upgraded 9 months behind
         | schedule, but paid us $270k, so not much to complain about
         | there.
        
           | wombatpm wrote:
           | So did you return the correct data with the 426 Code?
        
             | kerkeslager wrote:
             | No--the goal was to break the API so users noticed, with an
             | easy fix. A lot of users weren't even checking the HTTP
             | status codes, so it was necessary to not return the data to
             | make sure the API calls broke.
             | 
             | We did roll this out in our test environment a month in
             | advance, so that users using our test environment saw the
             | break before it went to prod, but predictably, none of the
             | users who were ignoring the warnings for the year before
             | were using our test environment (or if they were, they
             | didn't email us about it until our breaking change went to
             | prod).
        
         | mxey wrote:
         | > We've discussed doing brownouts where we fail everything for
         | an hour with clear error messages as to what is happening.
         | 
         | That sounds like the best option. People are used to the idea
         | that a service might be down, so if that happens, they'll look
         | at what the error is.
        
       | kerkeslager wrote:
       | Jesus, what a terrible idea. This is such a terrible idea that I
       | would not hire this guy based on this post alone.
       | 
       | What I want from code is for it to a) work, and b) if that's not
       | possible, to fail predictably and loudly.
       | 
       | Returning the wrong result is neither of the above. It doesn't
       | draw attention to the deprecation warnings as OP intended--
       | instead, it causes a mysterious and non-deterministic error,
       | literally the worst kind of thing to debug. The idea that this is
       | going to work out in any way calls into question the writer's
       | judgment in general. Why on earth would you intentionally
       | introduce the hardest kind of bug to debug into your codebase?
        
       | neilv wrote:
       | > _What if we intentionally made deprecated functions return the
       | wrong result ... sometimes? Every time it intentionally returns
       | the wrong result, it logs the deprecation warning.1_
       | 
       | What if we found that a highway overpass construction material
       | was suboptimal, and we want people to use superior materials, so,
       | every now and then, we send a chunk of concrete plummeting down
       | to the ground, to kill a motorist?
       | 
       | Thanks to deprecating like we mean it, they're going to replace
       | that overpass sooner than they would otherwise. You'll thank me
       | later.
       | 
       | From the https://sethmlarson.dev/deprecations-via-warnings-dont-
       | work-... that the post opens with:
       | 
       | > _This API was emitting warnings for over 3 years in a top-3
       | Python package by downloads urging libraries and users to stop
       | using the API and that was not enough. We still received feedback
       | from users that this removal was unexpected and was breaking
       | dependent libraries._
       | 
       | Entirely predictable.
       | 
       | Even many of those who saw the deprecation logging, and bothered
       | to make a conscious decision, didn't think you'd actually break
       | the API.
       | 
       | > _We ended up adding the APIs back and creating a hurried
       | release to fix the issue._
       | 
       | Entirely predictable.
       | 
       | Save yourself some anguish, and don't break API unnecessarily.
       | Treat it like a guarantee, as much as possible.
       | 
       | If it's a real problem for ongoing development, consider using
       | SemVer and multiple versions, like the linked article suggests.
       | (With the deprecated branch getting minimal maintenance: maybe
       | only select bug fixes, or only critical security fixes, maybe
       | with a sunset on even those, and a deprecation warning for the
       | entire library when it's no longer supported.)
        
       | dragonwriter wrote:
       | I don't think deprecation should come with hostile signalling
       | like this, but if it did, it should be consistent, and escalating
       | with subsequent releases, performance regressions on the
       | deprecated path, starting at least one release after the
       | deprecation warning, not wrong results.
       | 
       | And it should be explicitly mentioned in the deprecation
       | warnings.
       | 
       | (You don't want to break systems, but you want something people
       | who care about the system will investigate, and will quickly find
       | and understand the source of and understand what to do.)
        
       | mxey wrote:
       | It is wild to realize that this is the same author as
       | https://entropicthoughts.com/you-want-technology-with-warts
        
         | baobun wrote:
         | There is a new last line of TFA:
         | 
         | > In case the sarcasm isn't clear, it's better to leave the
         | warts. But it is also worthwhile to recognise that in terms of
         | effectiveness for driving system change, signage and warnings
         | are on the bottom of the tier list. We should not be surprised
         | when they don't work.
         | 
         | Looking at comments I guess everyone whooshed.
        
       | ryandrake wrote:
       | Ugh, I am finding it hard to express how much I hate this.
       | 
       | Software developers have enough treadmills they need to stay on.
       | Deliberately breaking backward compatibility in the name of
       | "deprecating something old" doesn't have to be one of them.
       | Please don't be that platform or library that deprecates and
       | removes things and makes me have to dust off that old software I
       | wrote in 2005 to move over to a different set of APIs just to
       | keep it working.
        
       | schnable wrote:
       | This is a bad idea. But in the same spirit, a bad but less bad
       | idea: require the user to actively enable the deprecated feature
       | via config or something, but have a known schedule to eventually
       | expire it (with a hard error, not randomly incorrect data) and
       | force the user to re-enable it. Causes some pain but not random,
       | hard to track down bug. More like dealing with expiring certs -
       | eventually, the user will want a permanent fix.
        
       | SuperNinKenDo wrote:
       | What about a sleep? Each release that the feature gets more
       | deprecated, the program adds a couple milliseconds of just
       | blocking. Less destructive, and gives a nice slow ramp up with
       | real but non-destructive consequences.
        
       | mxey wrote:
       | The article has a new note at the bottom:
       | 
       | > In case the sarcasm isn't clear, it's better to leave the
       | warts.
        
         | phyzome wrote:
         | Wow, that wasn't there from the start? That explains a lot of
         | the comments here.
        
       | dspillett wrote:
       | _> The response.getheader method in urllib has been deprecated
       | since 2023 ... When the method was eventually removed, lots of
       | code broke._
       | 
       | Two years doesn't seem long to me for a widely used project,
       | unless you have an LTS version that people needing more stability
       | can use, or you are upfront that your API support is two years or
       | less. Of course API support of less than two years is fine,
       | especially for a project that people aren't paying for, but
       | personally I would be quite explicit from the outset (in fact I
       | am with some bits I have out there: "this is a personal project
       | and may change or vanish on a whim, use it in any workflow you
       | depend on being stable at your own risk"). Or am I expecting a
       | bit much there?
       | 
       | If using semver or similar you are fine to break the API at a
       | major release point, that is what a major release means, though
       | it would be preferable for you to not immediately stop all
       | support for the previous major version.
       | 
       |  _> What if we intentionally made deprecated functions return the
       | wrong result ... sometimes?_
       | 
       | Hell no. A complete break is far preferable. Making your entire
       | API essentially a collection of undefined (or vaguely undefined)
       | behaviours is basically evil. You effectively render all other
       | projects that have yours as a dependency, also just collections
       | of vaguely defined behaviours. If your API isn't set in stone,
       | say so then people have nothing to complain about unless they
       | specifically ask you to keep something stable (and by "ask you to
       | keep something stable" I mean "offer to pay for your support in
       | that matter").
       | 
       |  _> Users that are very sensitive to the correctness of the
       | results..._
       | 
       | That is: any user with any sense.
       | 
       |  _> might want to swap the wrong result for an artificial delay
       | instead._
       | 
       | That is definitely more palatable. A very short delay to start
       | with, getting longer until final deprecation. How short/long is
       | going to be very dependent on use case and might be very
       | difficult to judge: the shortest needs to be long enough to be
       | noticeable to someone paying attention and testing between
       | updating dependencies and releasing, but short enough that it
       | doesn't completely break anything if someone updates and releases
       | quickly, perhaps to bring in a bugfix that has begun to affect
       | their project.
       | 
       | This is still evil, IMO, but a much lesser evil. I'd still prefer
       | the complete break, but then again I'm the sort of person who
       | would pay attention to deprecation notices, so unless you are a
       | hidden nested dependency I'd not be affected.
        
       | Lvl999Noob wrote:
       | The various projects that say something is deprecated but then
       | don't give a removal timeline or keep delaying the removal (or
       | even explicitly say it won't be removed, just remain deprecated)
       | are the cause of this problem.
       | 
       | IMO, any deprecation should go in the following steps:
       | 
       | 1. Decide that you want to deprecate the thing. This also
       | includes steps on how to migrate away from the thing, what to use
       | instead, and how to keep the existing behaviour if needed. This
       | step would also decide on the overall timeline, starting with the
       | decision and ending with the removal.
       | 
       | 2. Make the code give out big warnings for the deprecation. If
       | there's a standard build system, it should have support for
       | deprecation warnings.
       | 
       | 3. Break the build in an easy to fix way. If there is too much
       | red tape to take one of the recommended steps, the old API is
       | still there, just under a `deprecated` flag or path. Importantly,
       | this means that at this step, 'fixing' the build doesn't require
       | any change in dependencies or (big) change in code. This should
       | be a one line change to make it work.
       | 
       | 4. Remove the deprecated thing. This step is NOT optional!
       | Actually remove it. Keep it part of your compiler / library / etc
       | in a way to give an error but still delete it. Fixing the build
       | now requires some custom code or extra dependency. It is no
       | longer a trivial fix (as trivial as the previous step at least).
       | 
       | Honestly, the build system should provide the tools for this.
       | Being able to say that some item is deprecated and should warn or
       | it is deprecated and should only be accessible if a flag is set
       | or it is removed and the error message should say "function foo()
       | was removed in v1.4.5. Refer to the following link:..." instead
       | of just "function foo() not found"
       | 
       | If the build system has the option to treat warnings as errors,
       | it should also have the option to ignore specific warnings from
       | being treated as such (so that package updates can still happen
       | while CI keeps getting the warning). The warning itself shouldn't
       | be ignored.
        
       | shadowgovt wrote:
       | Well written, but author is at the risk of tripping over Poe's
       | Law, especially if readers don't read to the bottom.
       | 
       | Author's point is that their modest proposal (and its sibling,
       | introducing intentional delays in resolving the deprecated API
       | pieces) is a bad idea. Instead, author suggests that _making the
       | API change at all_ is begging the question  "Who does this API
       | serve?" It is, perhaps, _okay actually_ if the old system never
       | gets deprecated.
        
       | kazinator wrote:
       | Deprecation warnings are precisely that --- warnings --- so that
       | people have the option not to act on them. So, it is of little
       | surprise that users exercise one of the two available use case
       | scenarios, which is not acting.
       | 
       | There are sophisticated users who care about the quality of their
       | code and care about it breaking as infrequently as possible.
       | Those users follow warnings. Not only warnings that happen by
       | default; they use additional tooling to get extra warnings. The
       | follow up on warnings.
       | 
       | Deprecation warnings serve those people.
       | 
       | As for the others, who cares. "We generously told you this would
       | be removed, for years".
       | 
       | People who ignore warnings related to compatibility _and_ have a
       | workflow whereby your dependencies are not pinned down to
       | specific versions, in some project configuration file, so that
       | they are always getting the latest dependencies, are choosing to
       | inflict breakages on themselves.
        
       | burnt-resistor wrote:
       | Code churn is an evil, negative value activity. Design sanely and
       | carefully before settling upon a published, standard contract.
       | Churn of external-facing APIs should be extremely rare to solve
       | essential critical problems, not for pseudo-maintenance
       | bikeshedding. Also, the "it's a hobby" excuse doesn't fly.
       | 
       | tl;dr: Stop changing and breaking shit unnecessarily.
        
       | nitwit005 wrote:
       | I found the referenced article linked at the top interesting:
       | https://sethmlarson.dev/deprecations-via-warnings-dont-work-...
       | 
       | The underlying complaint seems to be about libraries, rather than
       | user behavior.
        
       | eslaught wrote:
       | The solution I've found is to make using the API a hard error
       | with an explicitly temporary and obnoxiously-named workaround
       | variable.                   WORKAROUND_URLLIB3_HEADER_DEPRECATION
       | _THIS_IS_A_TEMPORARY_FIX_CHANGE_YOUR_CODE=1 python3 ...
       | 
       | It's loud, there's an out if you need your code working _right
       | now_ , and when you finally act on the deprecation, if anyone
       | complains, they don't really have legs to stand on.
       | 
       | Of course you can layer it with warnings as a first stage, but
       | ultimately it's either this or remove the code outright (or never
       | remove it and put up with whatever burden that imposes).
        
         | tennysont wrote:
         | I heard a second-hand story about some team at Google who did
         | this, and named the variable something like:                 I_
         | ACKNOWLEDGE_THAT_THIS_CODE_WILL_PERMANENTLY_BREAK_ON_2022_09_20
         | _WITHOUT_SUPPORT_FROM_TEAM_X=1
         | 
         | a year before the deadline. I would be mildly amused by adding
         | _AND_MY_USER_ID_IS="<user_id>"
        
       | lisper wrote:
       | > The response.getheader method in urllib has been deprecated
       | since 2023 because the response.headers dictionary is what should
       | be used instead.
       | 
       | Then response.getheader should just do that. There is no reason
       | to expose the implementation to the user unless performance is
       | critical.
        
       | JaggerJo wrote:
       | Thats madness. Just remove deprecated functions after a
       | reasonable time period.
        
       | phyzome wrote:
       | << When the method was eventually removed, lots of code broke. >>
       | 
       | Well, removing it _earlier_ would just mean that lots of code
       | would break _earlier_...
        
       | RonanSoleste wrote:
       | Never do this on the job. Its called corporate sabotage and will
       | result in a lot of trouble for you. Its also a generally bad
       | idea. The whole point of deprecation is to let others choose a
       | moment to switch over on their own moment of choosing. If you
       | don't want to maintain it just remove it. It is far nicer
       | behavior. Don't force others in a debugging hell. It makes you a
       | bad person.
        
       | npunt wrote:
       | Filed under: trying to solve another domain's problem with only
       | the tools in your domain (this is almost always a bad idea)
        
       | mamcx wrote:
       | The sentiment is good but the solution is wrong.
       | 
       | The ideal flow, IMHO:
       | 
       | 1: Emit warning, and include if possible a deadline ("will be
       | removed in the next major version")
       | 
       | 2: After X time, BEFORE the deadline, turn it into a _compiler OR
       | linter error_ , but keep the code
       | 
       | 3: Do the appropriated notification in the channels about it of
       | impending doom
       | 
       | 4: Doom
       | 
       | If this is done correctly, we change the expectations from
       | "warnings LOL!" to "warnings are serious business" that is
       | missing in a lot of contexts
        
       | hacker_homie wrote:
       | Make the deprecated method slower with a function from the
       | deprecation release so the longer it goes on until it gets to
       | around a day.
       | 
       | then remove the function.
        
       | asveikau wrote:
       | > The response.getheader method in urllib has been deprecated
       | since 2023 because the response.headers dictionary is what should
       | be used instead.
       | 
       | Who cares? This is such a trivial example, where there is no
       | maintenance cost associated with leaving a dummy method in that
       | does a dictionary lookup. I understand there are times when
       | maintenance costs are substantial, but it's hard to take someone
       | seriously when this is their example.
       | 
       | The obsession with newness, and stigmatizing something that
       | doesn't conform to your sense of chasing newness, is really
       | silly.. _can you believe it 's been deprecated since 2023 and
       | someone still uses it????_ 2023 was not some kind of dark ages of
       | distant history.
        
       | tennysont wrote:
       | (Notwithstanding that this is a joke) Maybe it's just me, but I
       | read this as a solution that would be implemented internally at a
       | large company to distribute pain/accountability/tech-debt across
       | time to a team which might have high turnover. i.e., a way to
       | align incentives by punishing teams with bombs (via their
       | metrics) in their code, before the bomb actually detonates.
        
       ___________________________________________________________________
       (page generated 2025-12-11 23:01 UTC)