Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/docs/Coding-Standards/Dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ A pin has two independent parts; keep them separate.

The strongest posture combines both: a verified identity **and** a deliberate version. Identity is the integrity control; tightness is the velocity-versus-risk control below.

Before you choose a pin, decide whether you should add the dependency at all. For modules and libraries we build, the default is to **avoid introducing a new third-party dependency when the capability can reasonably be implemented with PowerShell, the .NET base class library, or code we own**. Every external DLL, package, or module adds another update stream, trust boundary, and failure mode to carry for the lifetime of the module. Spend a bit more effort up front if that keeps the shipped surface smaller and the ownership clearer.

## The locking spectrum

From tightest to loosest, each step trades safety for speed:
Expand Down
4 changes: 2 additions & 2 deletions src/docs/Coding-Standards/Functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ Before writing new logic, use what already exists — and build only what does n

- Prefer a built-in. If the language or runtime already does the job, use it instead of a hand-rolled version.
- Reuse an existing function instead of re-implementing it. If it is the weak link — too slow or imprecise on a hot path — fix it there so every caller benefits, rather than working around it.
- Take a dependency on a trusted module for a larger capability that already exists elsewhere; declare it explicitly instead of copying it in.
- Build it only when nothing fits — no built-in, no existing function, no trusted dependency. Size the build to the need: small logic lives inline where it is used; a larger, cohesive capability becomes its own module.
- Prefer shared code you own before introducing a third-party dependency, especially in a shipped library or module. An external package is a lasting trust and maintenance commitment, so only take it when the capability is large or specialized enough that owning it would be the worse trade.
- Build it only when nothing fits — no built-in, no existing function, no shared code you own, and no justified trusted dependency. Size the build to the need: small logic lives inline where it is used; a larger, cohesive capability becomes its own module.

## Signatures are contracts

Expand Down
3 changes: 2 additions & 1 deletion src/docs/Coding-Standards/PowerShell/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ Beyond the basics, these language-specific habits keep PowerShell correct and fa
- **Put `$null` on the left of a comparison** — `$null -eq $x`, never `$x -eq $null`. Against a collection the right-hand form *filters* rather than tests. Use `-contains` / `-in` for membership, never `-eq`.
- **Match text with the operator built for it.** Use `-like` for wildcard patterns and `-match` for regular expressions instead of hand-rolled string surgery; both default to case-insensitive, so add the `-c` prefix (`-clike`, `-cmatch`, `-ceq`) when a comparison must be case-sensitive.
- **Use the built-in intent checks for strings and wildcards.** Use `[string]::IsNullOrWhiteSpace($value)` for blank input and `[System.Management.Automation.WildcardPattern]::ContainsWildcardCharacters($pattern)` when deciding whether a value contains wildcard syntax.
- **Reuse before you build.** Work down the [reuse order](../Functions.md#reuse-before-you-build) — a built-in cmdlet or operator, then an existing function (public or private), then a trusted module (`#Requires -Modules` / `RequiredModules`), then your own code (small logic inline, a larger capability as its own module). State a dependency's acceptable versions as a [version range](Version-Constraints.md).
- **Prefer owned code over third-party dependencies in modules.** For a module we ship, exhaust PowerShell itself, the .NET base class library, and code we already own before adding an external module, DLL, or package. A third-party dependency is a long-term trust and maintenance commitment, so take it only when the capability is large enough or specialized enough that owning it ourselves is the worse trade.
- **Reuse before you build.** Work down the [reuse order](../Functions.md#reuse-before-you-build) inside the code we control — a built-in cmdlet or operator, then an existing function (public or private), then shared code we own, then new code. Reach for a trusted external module (`#Requires -Modules` / `RequiredModules`) only after that bar is cleared, and state its acceptable versions as a [version range](Version-Constraints.md).
- **PowerShell already *is* .NET; work at that level rather than wrapping it.** Casts, type accelerators (`[datetime]`, `[int]`), the `-split` / `-replace` / `-match` operators, and member methods (`.Trim()`, `.Where()`) all resolve to the base class library — using .NET means reaching for BCL types and methods for the computation, not restating everything as `[Namespace.Type]::Method(...)`. Where idiomatic PowerShell already resolves to the same .NET call, leave it; reach for explicit .NET only where it is measurably faster or more precise, and keep cmdlets and the pipeline where you need them for glue or readability.
- **Do the work in .NET when you implement it.** When you write the logic yourself — or fix an internal function that is too slow or imprecise on a hot path — call the .NET base class library directly instead of a cmdlet pipeline: `[System.IO.File]::ReadAllText($path)` over `Get-Content -Raw`, `[System.IO.Path]::Combine(...)` for paths, `[System.Text.StringBuilder]` for repeated concatenation, `[int]::TryParse(...)` for parsing. .NET methods are faster and their contracts are precise; keep cmdlets where their clarity is worth more than the speed. The next two rules are specific cases.
- **Suppress unwanted output with `$null = ...`** (or `[void]` for method calls), not `| Out-Null` — the pipeline form is markedly slower on hot paths.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ How the module is built.

Declare module dependencies using
[`#Requires -Modules`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires)
statements at the top of function files in `src/functions/public/` or `src/functions/private/` that require external modules.
statements at the top of function files in `src/functions/public/` or `src/functions/private/` that genuinely require external modules. For modules we build, the default is to avoid third-party module, DLL, and package dependencies when PowerShell, the .NET base class library, or code we own can carry the feature with reasonable effort.
[Build-PSModule](https://github.com/PSModule/Build-PSModule) collects every `#Requires -Modules` declaration across all
source files, de-duplicates the list, and writes it into the `RequiredModules` field of the compiled manifest
automatically. For the full range of supported syntax variants, see the
Expand Down