PowerShell / PowerShell

PowerShell for every system!
https://microsoft.com/PowerShell
MIT License
44.72k stars 7.24k forks source link

What is the right way to implement deprecation in PowerShell? #11674

Closed mklement0 closed 10 months ago

mklement0 commented 4 years ago

Follow-up from https://github.com/PowerShell/PowerShell/issues/11662#issuecomment-577861216:

Context:

Note: Deprecation in the context of PowerShell is always "soft" deprecation in the sense that, given the commitment to backward compatibility, features are never removed, so that old code continues to function. Instead, deprecation means discouraging use of a given feature, for various reasons: having been superseded by a superior alternative, general obsoleteness, security concerns.

Deprecation can be implemented in the following, potentially complementary ways:

The latter are currently implemented by a repurposing of the general System.ObsoleteAttribute attribute, whose purpose is to provide compile-time warnings (and optionally errors) about obsolete features: given that PowerShell code isn't compiled, the PowerShell engine explicitly surfaces Obsolete attributes on cmdlets or their parameters (but seemingly not SDK classes with the attribute) with a PowerShell warning at runtime.

Examples of features currently deprecated this way are Send-MailMessage and the -Raw parameter of the Format-Hex cmdlet; e.g.:

PS> 'foo' | Format-Hex -Raw
WARNING: Parameter 'Raw' is obsolete. Raw parameter is deprecated.
... # regular output

3>$null or -WarningAction Ignore can be used to suppress the warning, but old code written pre-deprecation will show the warning.

As an aside: The combination of the boilerplate part of the warning (Parameter 'Raw' is obsolete) with the attribute-specific message (Raw parameter is deprecated) could use some revising.


Relevant questions are:

SeeminglyScience commented 4 years ago

Thanks @mklement0! Copying my comment here so I can mark the one in the other thread as off topic.

While I agree that adding an ObsoleteAttribute would be annoying and probably not what we want here, I strongly disagree that it would be a breaking change.

If adding ObsoleteAttribute to anything is a breaking change, then that attribute is pointless.

It definitely can break things (I know there is a difference between something breaking the change contract and a change technically breaking a thing, but bear with me):

function Test-Something {
    [CmdletBinding()]
    param()
    end {
        if ($theWorldIsEnding) {
            $PSCmdlet.WriteWarning('some bad stuff is happening')
        }
    }
}

This is part of why I don't really like the warning system at all. Most of the things I would want to warn about are better off as a non-terminating error anyway.

If something is writing a warning, I'm either silencing it, or throwing on it. If I'm throwing on it with -WarningAction Stop, then adding ObsoleteAttribute will cause my script to always throw.

I know that if it's considered a breaking change than that makes the attribute useless, but that's how it feels currently. Personally I think ObsoleteAttribute should be moved to a design time warning only, maybe with error: true being the exception. That's how C# works as well, anything already built keeps on chugging but you're gonna know about it if you try to use it in something new.

The whole idea of attributes is that they behave as additive metadata.

That's true up until the point where something reads that metadata and changes behavior based on it. Adding Mandatory to a ParameterAttribute for example is for sure a breaking change.

SeeminglyScience commented 4 years ago

Simply emitting a new warning message can also break systems that detect success/failure based on stdout/err.

For example, script based application detection methods in SCCM. The SCCM client will invoke a PowerShell script and use stdout/err to determine if the subject application was installed correctly. Here's a table (from About custom script detection methods):

Zero exit code
STDOUT STDERR Script result Application detection state
Empty Empty Success Not installed
Empty Not empty Failure Unknown
Not empty Empty Success Installed
Not empty Not empty Success Installed
Non-zero exit code
STDOUT STDERR Script result Application detection state
Empty Empty Failure Unknown
Empty Not empty Failure Unknown
Not empty Empty Failure Unknown
Not empty Not empty Failure Unknown

So since warning counts as stdout, if a detection method uses a command that has been deprecated, all of those applications will start reporting as if they are already installed.

iSazonov commented 4 years ago

GitHub search results:

I still believe that the transfer of the system to a new version involves testing. I don’t think anyone can easily jump from 5.1 version to 7.0.

To migrate a large system like SCCM MSFT team and consumers must test all used scripts. I guess we need a special label for already tested scripts and engine could report still not tested scripts.

For warning messages we could play with preference level to ignore such messages in scripts and show in console session.

SeeminglyScience commented 4 years ago

GitHub search results:

  • -WarningAction - 8472
  • -ErrorAction - 400857

That's honestly way more than I expected to see. I would have guessed like low 300s.

I still believe that the transfer of the system to a new version involves testing. I don’t think anyone can easily jump from 5.1 version to 7.0.

To migrate a large system like SCCM MSFT team and consumers must test all used scripts.

Well yeah for sure. I've supported many breaking changes in the past and will continue to do so - when the benefit outweighs the risk.

You could argue (and I'd find it hard to disagree) that the risk is pretty small for adding a warning. That said, it's often discussed as zero risk, like it's an interactive only change. The risk is definitely higher than zero, and in my opinion higher than should be acceptable for the simple act of marking something as obsolete. I'm mainly suggesting that a design time warning should be sufficient.

dragonwolf83 commented 4 years ago

A new Obsolete or Deprecate stream could be added that is only updated by the System.Obsolete attribute. That prevents breaking changes with anyone using -WarningAction and separates out code changes from scripting logic.

The SCCM scenario is not likely an issue. Warning and Verbose are not redirected to standard out by default so it should not be breaking their detection logic. You can redirect those streams individually or redirect all streams to standard out, but then Verbose would break you way before anything else does. Anyone redirecting those streams likely is already handling error detection properly.

SeeminglyScience commented 4 years ago

A new Obsolete or Deprecate stream could be added that is only updated by the System.Obsolete attribute. That prevents breaking changes with anyone using -WarningAction and separates out code changes from scripting logic.

That's a cool idea, but a lot of work. Problems with that approach aside, they're realistically not going to do that.

The SCCM scenario is not likely an issue. Warning and Verbose are not redirected to standard out by default so it should not be breaking their detection logic. You can redirect those streams individually or redirect all streams to standard out, but then Verbose would break you way before anything else does. Anyone redirecting those streams likely is already handling error detection properly.

When I say stdout, I'm not referring to PowerShell's output stream. I'm referring to the console process standard output. Anything that writes to the console window and isn't classified as an error message is written to standard output.

Open up cmd.exe and run this

powershell -nop -noni -c "Write-Warning visible" > test.log

In the file will be "WARNING: visible".

dragonwolf83 commented 4 years ago

When I say stdout, I'm not referring to PowerShell's output stream.

I was too, but I see $WarningPreference defaults to Continue so it is redirecting by default to standard out but Verbose output is not unless you specify it.

Another option is to just write to the console only and not implement as a full stream. I don't believe the old Write-Host from before PS 5 wrote to standard out since the whole issue was that it wrote to the console directly. If that is the case, surfacing that logic shouldn't be too hard for this special case.

SeeminglyScience commented 4 years ago

Another option is to just write to the console only and not implement as a full stream. I don't believe the old Write-Host from before PS 5 wrote to standard out since the whole issue was that it wrote to the console directly. If that is the case, surfacing that logic shouldn't be too hard for this special case.

The issue was that it wasn't going through a PowerShell controlled stream. It did still write to stdout though.

mklement0 commented 4 years ago

To illustrate that with a quick example: The following cmd.exe command has no output, because not just Write-Host, but [Console]::WriteLine() goes to stdout too:

C:\>pwsh -nop -c "write-host hi; [console]::writeline('ho')" > NUL

As an aside: That all streams, including the error stream, go to stdout is, of course, a problem, but changing that would be a breaking change: https://github.com/PowerShell/PowerShell/issues/7989#issuecomment-430854508

I'm mainly suggesting that a design time warning should be sufficient.

I agree; in order to implement that we'd have to do the following (I can't speak to the technical feasibility):

iSazonov commented 4 years ago

I see the discussion is only about"Runtime warnings".

I think that the SCCM example is not successful, because SCCM starts an external process. Sometimes it seems to me that it has no design at all :-). Since PowerShell merges everything into one output stream, this will always be a problem, regardless of whether there are warnings. This mechanism is, by definition, completely unreliable. Opposite look SC Orchestrator. It doesn't use external process, it hosts PowerShell and as result has not the issue.

Now we should look how deprecation is used. We have 2 main scenario - user console session and application session (I mean all without user interaction). As user I'd accept informational messages that a cmdlet or feature will be removed from future version as non-secure (Invoke-Expression) or non-supported (Send-MailMessage). But it is important that the message offers a replacement (link to docs) otherwise it will useless and annoying. User will switch to proposed alternative and will do not get warnings.

For applications the warnings are pointless. Main concern in the discussion is that warnings can break something. I believe we are thinking not in right direction because besides this minimal risk there are many, many changes that represent a real risk. Running blindly any script, module or application on new PowerShell version is dangerous and may be destructively. Users should test their scripts in sandbox before run in live business environment. Right direction is that we should protect users and enforce them to test scripts. Proposal is to introduce PowerShell adoption mode to prevent users from running non-tested scripts.

mklement0 commented 4 years ago

Since PowerShell merges everything into one output stream, this will always be a problem, regardless of whether there are warnings. This mechanism is, by definition, completely unreliable.

This is a separate problem, which can be tackled via the planned separate PowerShell executable for not loading $PROFILE by default - see #8072. The right behavior is to send all streams other than the success output stream to stderr, which is the only other native stream available.

it hosts PowerShell

This is not just about SCCM. It is unrealistic and unreasonable to expect all external (build, CI / CD, ....) tooling to host PowerShell, so the problem will persist, even with the above fix in place.

Aside from that, even a host that checks streams separately could be thrown off by the appearance of new warnings.

user console session

Agreed, in interactively submitted individual commands (as opposed to scripts) that print to the host it would be helpful for the engine to surface deprecation warnings, along with helpful links.

Proposal is to introduce PowerShell adoption mode to prevent users from running non-tested scripts.

Interesting - I suggest you create a new issue for that.

But if I interpret your comments correctly, you agree that there is no need for runtime deprecation warnings for unattended (update: and captured / redirected) execution, correct?

iSazonov commented 4 years ago

But if I interpret your comments correctly, you agree that there is no need for runtime deprecation warnings for unattended execution, correct?

I find it useful for users in interactive session and pointless for scenarios like task scheduler (here we could only write a log event and telemetry if we need).

SeeminglyScience commented 4 years ago

One option would be to only write the warning when CommandOrigin is Runspace and -NonInteractive was not specified. That would eliminate the majority of risk.

lukeb1961 commented 4 years ago

As a IT admin, if I see 'deprecated' in any way/shape/form you finally decide on, I am going to expect to see 6 different alternatives/examples in help showing me why it is deprecated and what are my options to change to the New/Right/Approved way. Everything you guys don't like about PowerShell, you have to tell me why and how to change to the New Way. Just thought I'd throw that in now rather than later...

iSazonov commented 4 years ago

One option would be to only write the warning when CommandOrigin is Runspace and -NonInteractive was not specified. That would eliminate the majority of risk.

We could create an internal method for this and use it in Send-MailMessage and Invoke-Expression BeginProcessing().

SeeminglyScience commented 4 years ago

One option would be to only write the warning when CommandOrigin is Runspace and -NonInteractive was not specified. That would eliminate the majority of risk.

We could create an internal method for this and use it in Send-MailMessage and Invoke-Expression BeginProcessing().

Forgot about invoke expression. That one definitely shouldn't warn interactively since that's the only scenario it makes sense to use it for. And tbh what I proposed would be pretty hard to reason about for newer folks. I'm back to thinking a design time warning is the right route.

rjmholt commented 4 years ago

Tagged the @PowerShell/powershell-committee so that they can discuss this, since I think they need to be aware of our desire to standardise deprecation in PowerShell on a method that is discoverable but is unlikely to break code.

joeyaiello commented 4 years ago

Thank you for the breakdown here, @mklement0. You've articulated really well our difficulty in being anything but tactical and reactionary when it comes to deprecated (or "pseudo-deprecated") components.

Before we get too far along on the discussion, can we start enumerating all the deprecated, almost-deprecated, or "wish we could have deprecated before we broke" features/components from PS 5.1 to 7? Off the top of my head:

rjmholt commented 4 years ago

Some thoughts I want to throw carelessly into the ether:

I think @mklement0 enumerated the options for deprecation well (but everyone please feel free to add new ideas for communicating deprecation). Two thoughts on that:

So in terms of what it would take to resolve this issue in my mind, I would list the following:

riverar commented 4 years ago

re: terminology In this context, can we define obsolete and deprecated? There appears to be some confusion (e.g. the first comment uses obsolete/deprecated interchangeably which is very confusing).

re: signaling deprecation/obsolescence I think it makes sense to think about how this is handled elsewhere. Let's look at Win32 APIs. Those APIs—some deprecated—certainly don't function differently in an attempt to signal lifecycle status/policy to the user. This ensures maximum app compatibility until the very last moment. The working assumption here is that the user is aware of the API's lifecycle via other side channels (e.g. docs, blogs, tooling warnings and errors, crashes, etc).

❌ I do not support the emission of any data to any stream (e.g. screen, file, network) at runtime to signal intent. This will break apps.

✔ I do support updates to dev tooling and docs to communicate this class of information prior to making changes.

PowerShell Core follows the Modern Lifecycle Policy, which requires upgrades after 6 months (and patch installs after 30 days). The vehicle for these Cmdlet changes is already in place and active. Use it!

Windows PowerShell instead falls back onto the OS lifecycle. Want a stable platform for your scripts to run for years unimpeded? Use a long-term servicing branch of Windows and Windows PowerShell.

SeeminglyScience commented 4 years ago
  • PSScriptAnalyzer, while owned by the PowerShell team, is a very community-driven tool. Most of its rules have been written with or guided by community input, and I wouldn't say they have an official capacity. That is to say, if we want PSSA to be a deprecation vector, I would suggest we create a new namespace for "official" deprecation rules. I say this since some rules have a style opinion, and the PowerShell team tries not to prescribe styles too much (at least not in my time).

Yeah I agree. Just to clarify, when I suggest that obsolescence should be a design time warning, what I'm suggesting is:

  1. Remove the run time warning for ObsoleteAttribute
  2. Add a rule to PSSA that checks for said attribute

What is and isn't deprecated is still dictated by the author, PSSA just delivers the news.

rjmholt commented 4 years ago

Add a rule to PSSA that checks for said attribute

The issue I see here is that this relies on the PowerShell version analysing the script (which is something I don't like about PSSA in general). Perhaps that's not the end of the world, or even a good thing in this case. But my preference would be for PSSA to have a catalogue of deprecated invocations and us keeping that up to date.

Let's look at Win32 APIs

Those are very low level APIs; there's really no mechanism to decorate them for deprecation (at least not one that wouldn't slow some APIs down by orders or magnitude). Conversely, the .NET APIs, which PowerShell is more directly built on, emit compile-time warnings for every static use of an API with an ObsoleteAttribute on it.

I don't like emitting warnings at runtime for deprecated APIs though. PowerShell's "compile time" is essentially at runtime (or at least, isn't dependable enough a stage to put warnings at). I still don't fully agree with the breaking argument -- warnings are differentiated from errors in that they are ignorable (open the dev console in any webpage and see how many warnings show up), they are also configurable and redirectable, ObsoleteAttributes have emitted warnings for some time in PowerShell, and other data streams get used in the background by PowerShell all the time. However, emitting warnings at runtime for this is both ugly and inefficient (since every invocation must look for ObsoleteAttributes).

I'm also wary that most users aren't using PSScriptAnalyzer or really all that much in the way of tooling. But I suspect that tooling and documentation is the best answer we have here. To get to that point though, PSSA is going to need some investment, both in terms of making it a better tool (which is planned to be worked on but will take time and could always use help) and also in terms of helping PowerShell users discover, configure and use it.

I also suspect that in documentation, we should have a one-stop-shop for enumerating deprecated APIs so that they are really discoverable.

Also, nobody's said otherwise, but I feel like I should add that in terms of SDK/development experience, the ObsoleteAttribute is still useful (arguably more so) to let module/host authors know what APIs are deprecated.

rjmholt commented 4 years ago

I'm also wary that most users aren't using PSScriptAnalyzer or really all that much in the way of tooling

After mentioning this briefly to @joeyaiello, he raised the valid point that a reasonable proportion of users may never even use PowerShell non-interactively.

While I think tooling works well for scripts to be deployed and run non-interactively, it doesn't provide a mechanism to let users know that the commands they're using or habits they're building are deprecated. Getting past runtime warnings here is hard. A possible alternative might be in PSReadLine (like if it coloured deprecated commands differently or put a warning in the completion info section), but that's really spitballing.

The other problem with not emitting runtime warnings is that statically analysing for deprecated invocations isn't always possible. It's entirely possible to use a deprecated API in a way that a tool analysing the AST (be it PSSA or PSReadLine) wouldn't pick up (but which the engine always catches).

riverar commented 4 years ago

Throwing in some data: PowerShell had a similar predicament with unapproved verbs and made them opt-in by default / added a flag to hide them. So there's emission precedent.

KevinMarquette commented 4 years ago

I currently use ObsoleteAttribute when cleaning up old scripts. I like that I can see the warning when running Pester tests. When other people consume my scripts, they get the warnings when using those attributes. I can scan execution log files for the warning messages produced. I have not ran into any issues with the warnings produced this way. It has been a great tool for me when refactoring internal projects. I would like a way to specify Deprecated vs Obsolete.

Having PSSA identify the use of an ObsoleteAttribute is a great idea. I hacked together a script to scrape my own code for use of obsolete attributes but never took it so far to make a PSSA rule for it.

However we implement deprecation in PowerShell, it would be nice if module authors can also make use of it.

BrucePay commented 4 years ago

@joeyaiello

Encoding changes between 5.1 and 6

I'm not sure how we would even mark this type of thing as deprecated.

FireInWinter commented 4 years ago

I'm for never showing a message interactively. Just tried Send-MailMessage in PowerShell 7rc3 and got the news that it is obsolete, but gives me no guidance on what to use instead. This isn't something I ever want consumers on my modules to see interlaced with other output. It's a bad experience and doesn't even offer a solution. Seeing it when I'm writing something is a lot more useful as I see it as the developer and not as a consumer/user. As a developer I can plan/understand that I will eventually have to replace it with something else.

rjmholt commented 4 years ago

This isn't something I ever want consumers on my modules to see interlaced with other output

# Suppress warnings emitted by redirecting the warning stream
Send-MailMessage -From me@outlook.com -To you@outlook.com 3>$null

but gives me no guidance on what to use instead

I believe the obsolescence message is the following:

WARNING: The command 'Send-MailMessage' is obsolete. This cmdlet does not guarantee secure connections to SMTP servers. While there is no immediate replacement available in PowerShell, we recommend you do not use Send-MailMessage at this time. See https://aka.ms/SendMailMessage for more information.

If you follow that link, there is a recommendation. It does look like more recommendations could be given. I'm sure PRs would be accepted to improve that document. Sorry, I just realised that's a .NET deprecation notice. As users of their platform, we're bound by their decisions. And if we don't communicate deprecations to our users, we manage an impossible asymmetry.

Seeing it when I'm writing something is a lot more useful as I see it as the developer and not as a consumer/user

Unfortunately this is a hard problem to address in a scripting language with no compile step. Many script invocations are not made by developers but in an interactive scenario, in which case PSScriptAnalyzer won't address the need to inform PowerShell users that the command they just used is something they should reconsider. In places like reddit and Twitter, users still ask about PSSnapIns and WMI cmdlets in the context of PowerShell 7 — communicating obsolescence is hard.

GitHub
dotnet/platform-compat
Roslyn analyzer that finds usages of APIs that will throw PlatformNotSupportedException on certain platforms. - dotnet/platform-compat
mklement0 commented 4 years ago

@rjmholt, re 3>$null / -WarningAction SilentlyContinue: I think the point is that warnings shouldn't suddenly start showing up in deployed code written before a feature became obsolete.

@FireInWinter, re:

I'm for never showing a message interactively.

I can't speak to the technical feasibility (@SeeminglyScience has hinted at a solution), but to me it makes sense to show the warning in direct interactive use (only), e.g., if you submit 'foo' | Format-Hex -Raw directly at the prompt - as opposed to doing it inside a script. This would alert non-scripters to the deprecation as well, and alert scripters early.

To turn the warning off, you could use $PSDefaultParameterValues.Add('Format-Hex:WarningAction', 'SilentlyContinue') (though note that it will silence all potential warnings emitted by the cmdlet).

As @rjmholt notes, without a compilation step we cannot really ensure that scripters will see the warning, but being vocal about the recommended tooling (PSSA, directly or implicitly via VSCode) would help.

Of course, someone who only ever invokes scripts / module functions / cmdlets would then never get to see the warnings, but I think it's fair to expect scripters (command authors) to take responsibility for deploying updated commands that avoid the deprecated features.

This could be complemented with an opt-in mechanism (preference variable) to always show deprecation warnings at runtime, which would address @KevinMarquette's scenario, though not by default; similarly, it addresses the limitations of static analysis that PSSA can provide, as noted by @rjmholt.

Additionally, a centralized online deprecation "registry", as mentioned by @rjmholt, sounds like a great idea, especially for the wholesale removals / fundamental breaking changes mentioned by @joeyaiello , such as the removal of workflows and the change in default character encoding.


Re terminology:

While not really formalized, the term deprecated - not obsolete - has historically been used in PowerShell (e.g., for the ModuleToProcess module-manifest entry), generally with the "soft" meaning outlined in the OP:

Why it is not recommended anymore, which could be one of several reasons, should be detailed in the specific messages - as I agree with @rjmholt that trying to formalize degrees of deprecation would introduce too much complexity; as @joeyaiello and @rjmholt have noted, some features effectively have gone away, notably in the transition to PS Core, but that's the exception, from what I understand.

Use of the ObsoleteAttribute .NET attribute is an implementation detail, whose terminology happens not to align with PowerShell's; publicly, these terms shouldn't be mixed - only deprecated should be used, which means that the boilerplate part of deprecation warnings shouldn't say "is obsolete" - it should say "is deprecated", which requires changing the UseOfDeprecatedCommandWarning and UseOfDeprecatedParameterWarning messages (others?)

SteveL-MSFT commented 4 years ago

@PowerShell/powershell-committee discussed this and we agree the current approach is inadequate and needs a consistent design. We'll follow-up with individual comments/ideas.

rjmholt commented 4 years ago

I think the point is that warnings shouldn't suddenly start showing up in deployed code written before a feature became obsolete.

I do understand that, but that is the same as saying "deployed code should never become obsolete". Eventually features, libraries, platforms can become obsolete. You might deploy a security library today and have it become obsolete in the future. What's more, the obsolescence warning will only appear if PowerShell itself is updated, at which point the deployment should be re-evaluated for compatibility.

SteveL-MSFT commented 4 years ago

It may make sense to introduce a $DeprecationActionPreference with default value of Continue which would emit the warning message as it exists today. It can be set to Stop to turn the warnings into errors, Inquire to prompt, SilentlyContinue and Ignore to be silent.

vexx32 commented 4 years ago

That implies a whole other stream, though, which is currently not true. I don't think we need to increase the potential confusing factors here. 🙂

joeyaiello commented 4 years ago

That was my thought too, @vexx32, but we also proposed that a NoteProperty on the Warning stream might be better. Then they can be squashed with all other warnings, queried on in logs, etc.

@BrucePay also raised that a good lens to look through in the future is along the lines of "consumers" (e.g. interactive users and script executors) as opposed to "developers / authors" who are building modules and scripts they need to be well maintained over a period of time.

KevinMarquette commented 4 years ago

For the author, we could make a message visible with -Debug messages, Set-StrictMode latest make its usage an error, PSScriptAnalyzer issue a warning or error, call it out in the documentation, and have the PowerShell team blog it. Test-ModuleManifest,Publish-Module, and Publish-PSResource throw errors with an switch to bypass. PSGallery can send notifications to module authors. Issue warning in Install-Module or Install-PSResource when a module is installed. Optionally Import-Module can issue a warning on import.

For the consumer, for the first major version after it's actually gone, throw a specific error to communicate why their script is broken instead of the standard parse error. This also helps authors that run preview versions to discover it early.

If all that doesn't get the authors attention, then it's unlikely they would have changed it before it breaks. We can't say we didn't give our best effort.

As far as implementation details, having an attribute that can be used on functions, parameters, variables, classes (and their methods and properties) that's available in script modules gives authors the ability to utilize this feature. It would be good if the attribute on the functions,classes, (or modules?) can specify properties and members that have been removed.

I prefer the attributes but as an alternate implementation, use something in the module manifest to indicate what's on the way out or already gone so it's handled appropriately and gives other authors a single place to look in a module to see all these settings in one place. This would help PowerShellGet integration into the notification effort.

joeyaiello commented 4 years ago

One thing I want to clarify as we think through this is that we should really scope the conversation to notifying the user of deprecation, rather than actually building a path to actually removing things from the engine. I was very convinced by @BrucePay's argument offline that we really can't ever remove anything from PS7 given it's LTS nature and stability long-term.

One idea I had today (inspired by some of @JamesWTruher's suggestions) is that we could create a parallel to experimental features called "deprecated features". They'd be on by default to keep breaking changes from occurring, but with Get/Enable/Disable-DeprecatedFeature sets, you'd get:

I'm planning on writing up a specific issue for just this idea, but I wanted to float it here first to move the ball forward on getting it shot down ;)

vexx32 commented 4 years ago

I think long term, we actually have an unanswerable need to be able to break things that used to work in order to build better things.

Otherwise, we simply end up with mountains upon mountains of technical dept, half-written features, semi-supported use cases that never actually worked properly, just "well enough" for some limited usage, etc., etc., etc.

If breaking changes/deprecation of features is never going to be OK, PowerShell will eventually just become another bloated tool that does too many things not well enough, and will ultimately be superceded by more effective and streamlined tools.

Part of the reason semver even exists is to help developers communicate that across some version jumps, things may break. It's a tool we should be OK with using. Nobody is forcing folks to move to new versions until they're ready to do so; at some level, we need to be willing to remove old code, or the project as a whole will gradually become effectively impossible to maintain.

Just my 2 cents.

rjmholt commented 4 years ago

To my mind we need a process that allows breaking changes and API removal. That's related to deprecation but isn't the same thing. Deprecation is just a warning system, and it might warn about breaking changes or it might warn about other things.

I think to break things the right way, we need:

Today we don't really have any of these, other than possibly experimental features for the first, and I think it would require a fair amount of work to get them. If we decided to take it on, we'd need to find the time to invest in it.

I should also say that on the edge of development there is always a bias for moving forward, but as a shell, a programming language and a platform, PowerShell needs to be mindful of the full lifecycle of changes it introduces, and should look around to see how other software we compare ourselves to behaves. How often and in what way does bash, zsh, C#, .NET or Python take a breaking change?

As @joeyaiello says though, conversation about breaking things should be moved to a new issue. Deprecation is a warning system.

iSazonov commented 4 years ago

I wonder how many TMA we are talking about? Can we take the SDK and classify all the APIs to understand this?

Also, if we are only talking about warnings, it’s enough to set the obsolete attribute and add XML comment.

rjmholt commented 4 years ago

Moving the conversation about how we make breaking changes to https://github.com/PowerShell/PowerShell/issues/13129

rjmholt commented 4 years ago

.NET has written up an interesting document about obsoletion which might be worth comparing to our discussions here

SteveL-MSFT commented 4 years ago

@PowerShell/powershell-committee discussed this today. Although no conclusion, we did agree on a few things:

We believe this feature requires a RFC to be authored

iSazonov commented 4 years ago

We could do not complicate and simply continue to use Experimental Features but have "Deprecate" in an experimental feature name.

microsoft-github-policy-service[bot] commented 10 months ago

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

microsoft-github-policy-service[bot] commented 10 months ago

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

microsoft-github-policy-service[bot] commented 10 months ago

This issue has not had any activity in 6 months, if this is a bug please try to reproduce on the latest version of PowerShell and reopen a new issue and reference this issue if this is still a blocker for you.

microsoft-github-policy-service[bot] commented 10 months ago

This issue has been marked as "No Activity" as there has been no activity for 6 months. It has been closed for housekeeping purposes.