[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)