Great Debate: Pipeline Coding Syles

by Dave Wyatt


A good programmer or scripter should always try to produce code that is easy to read and understand. Choosing and consistently applying a strategy for indentation and bracing will make your life, and possibly those of your co-workers, much easier. (Unless, of course, you’re that guy who prides himself in writing code that looks like a cat walked across his keyboard, and cackles any time someone tries to understand it.)

Much of PowerShell’s syntax can borrow coding conventions from C-style languages, but the pipeline is something new. Below are two pipelines formatted a few different ways. Which styles do you find to be the easiest to read? In the second pipeline, which contains an embedded multi-line script block, would your choice be any different if the script block were much longer? For instance, if you couldn’t see both the beginning and the end of the pipeline without scrolling. Do you have another way of formatting these bits of code that you like better?

Remember, there is no right or wrong answer here. The idea is just to generate discussion, and perhaps to help people produce more readable code.

# A simple pipeline with each command fitting on a single line.
# Line breaks after the pipe character.

Get-ChildItem -Path $home\Documents -File |
Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } |
Select-Object -ExpandProperty Name

Next-Command

# The same pipeline, this time indenting each line after the first one.

Get-ChildItem -Path $home\Documents -File |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } |
    Select-Object -ExpandProperty Name

Next-Command

# This time, using backticks at the end of each line, and placing the 
# pipe character at the beginning of the next line.

Get-ChildItem -Path $home\Documents -File `
| Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } `
| Select-Object -ExpandProperty Name

Next-Command

# And again, with indentation

Get-ChildItem -Path $home\Documents -File `
    | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } `
    | Select-Object -ExpandProperty Name

Next-Command

# A slightly more complex pipeline involving an embedded script block
# passed to ForEach-Object.  Does the pipe symbol after a closing brace,
# potentially much farther down in the code from where the pipeline
# started, change your opinion on what's the easiest to read?

Import-Csv -Path $inputCsvPath |
ForEach-Object {
    # Transform objects in some way
} |
Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

# The same three variations of style involving indentation and backticks:

Import-Csv -Path $inputCsvPath |
    ForEach-Object {
        # Transform objects in some way
    } |
    Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

Import-Csv -Path $inputCsvPath `
| ForEach-Object {
    # Transform objects in some way
} `
| Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

Import-Csv -Path $inputCsvPath `
    | ForEach-Object {
        # Transform objects in some way
    } `
    | Export-Csv $outputCsvPath -NoTypeInformation

Next-Command

About the Author

About Dave Wyatt

Dave Wyatt is an IT professional who has been in the industry for about 14 years, both as a software developer and as a systems administrator or engineer. He currently works for a retail company, responsible for Windows-based point of sale and back office solutions in 2500+ stores across North America and Europe. In 2014, he received PowerShell.org's "PowerShell Hero" and Microsoft's MVP (PowerShell) awards.

This entry was posted in Great Debates and tagged , , on by .

9 thoughts on “Great Debate: Pipeline Coding Syles

  1. Terry E Dow

    My natural style developed to your second sample:
    # The same pipeline, this time indenting each line after the first one.
    I visualize it as a shallow tree (a bush maybe) with a single root and a long branch. The pipeline at the end is a native command line continuation character for PowerShell, and for me ;-). No need for infinite indentations, just one per pipeline root. Nested pipelines root get their indentation for their branch.

  2. Matt Tilford

    The approach that i try to maintain is: if i am inside a new construct then i should indent. The example that shows that is

    Import-Csv -Path $inputCsvPath |
    ForEach-Object {
    # Transform objects in some way
    } |
    Export-Csv $outputCsvPath -NoTypeInformation

    I have used some exceptions, where i had an if..else block with a few words of code in the code block i did each option on a single line.

  3. Dave Wyatt Post author

    There doesn’t seem to be much love for the idea of placing pipe characters at the beginning of a line. I don’t actually use that style; it’s something that I saw on the original forum post that came before this blog entry. Just to play the devil’s advocate, though, I can see two potential benefits to this style (the first of which was pointed out by the same person who suggested the style):

    1) If you forget to type a pipe character at the end of a line, it’s still valid PowerShell syntax. Depending on the next command after the missing pipe character, the script might even still run, with unexpected results. That kind of error can be annoying to find and correct. On the other hand, if you forget the backtick character (or the pipe character on the following line, for that matter), you’ll get an error right away due to invalid syntax.

    2) To me, it does seem easier to spot the where the pipeline begins and ends when the pipe characters are at the beginning of a line instead of at the end. Like indentation, it provides a way for my eyes to group statements without having to read them from beginning to end, or without having to check the end of each line for a pipe symbol.

  4. Al Dunbar

    I use example 2, as I find the indentation helpful. But it does raise a few issues of consistency when followed by a script block that has its own indentation…
    I agree that adding a virtually invisible backtick and moving the pipe to the beginning of the next line is a waste of a perfectly good continuation character.

  5. Mike Koehler

    I always write these with the pipe at the end of the line and the next line indented. I indent simply to make it clearer where the pipeline ends. Backticks to continue a line are evil.

    So for the first example I would prefer this:

    Get-ChildItem -Path $home\Documents -File |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } |
    Select-Object -ExpandProperty Name

  6. Richard Siddaway

    Get-ChildItem -Path $home\Documents -File `
    | Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-120) } `
    | Select-Object -ExpandProperty Name

    is good code
    - The extra work with the backtick – which isn’t always easy to spot
    - The pipe is a line continuation character – why introduce a second one

    Indenting on a single pipeline I don’t really think adds much

    This is still the easiest to read

    Import-Csv -Path $inputCsvPath |
    ForEach-Object {
    # Transform objects in some way
    } |
    Export-Csv $outputCsvPath -NoTypeInformation

    Adding extra work that brings no gain with the others

    I would always go for the simplest approach on the principle that if you have multiple people working on the code its easier to get them all to stick to that formatting. It also follows accepted best practice

    1. Dave Wyatt Post author

      The first option is how I’ve been writing code so far, as well. The idea behind each of the alternative styles is to try to enhance readability by making it easier to see, at a glance, where one pipeline ends and the next begins (the same benefit you get from using indentation for the contents of any block of code).

Leave a Reply