Monthly Archive

Categories

Monthly Archives: April 2018

Code reviews and Iron Scripter

Many organisations use code reviews to help ensure a quality outcome. At the recent PowerShell Summit we ran a scripting competition – Iron Scripter. I’ve had a thought on how code reviews and Iron Scripter have something in common. Something that could lead to a better code review.

Iron Scripter involved the attendees splitting into 3 factions – each with its own philosophy:

Battle faction produce code that’s good enough to do the job then move onto the next problem.

Daybreak faction produce beautiful code that is easy to read and understand

Flawless faction produces code that “never” fails – it has all of the error handling and validation that you could wish for.

 

How does this help your code reviews?

Get people to adopt one of the above points of view (POV) either by choosing what comes naturally to them or by assigning roles. They then review the code from that POV:

Battle faction – does it get the job done

Daybreak faction – is it easy to understand and therefore maintain

Flawless faction – are errors handled

 

You can add other POV as desired and you don’t have to use the faction names. By getting people to review the code from differing POV you will have a better code review and therefore a better product.

Positional parameters

Positional parameters allow you go use a function of cmdlet without specifying the parameter names. The values you supply are assigned to the correct parameters based on their position.

If you look at the documentation for PowerShell you’ll see some confusion as to whether position 0 or position 1 is the first assigned position. Hopefully, these experiments will explain it all.

 

By default parameters are positional. So values are assigned to parameters based on the order of parameter definition.

function pa {
param (

[int] $x,

[int] $y
)

"`$x = $x"
"`$y = $y"

$x * $y

}

PS> pa -x 2 -y 3
$x = 2
$y = 3
6

PS> pa 2 -y 3
$x = 2
$y = 3
6

PS> pa 2 3
$x = 2
$y = 3
6

PS> pa -x 2 3
$x = 2
$y = 3
6

 

When you assign a position to one of more parameters those parameters without a positional assignment become non-positional and need to be explicitly defined

PS> pb -x 2 -y 3
$x = 2
$y = 3
6

PS> pb 2 -y 3
$x = 2
$y = 3
6

PS> pb 2 3
pb : A positional parameter cannot be found that accepts argument '3'.
At line:1 char:1
+ pb 2 3
+ ~~~~~~
+ CategoryInfo : InvalidArgument: (:) [pb], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,pb

PS> pb -x 2 3
pb : A positional parameter cannot be found that accepts argument '3'.
At line:1 char:1
+ pb -x 2 3
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [pb], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,pb

 

Alternatively

function pc {
param (

[Parameter(Position=1)]
[int] $x,

[int] $y
)

"`$x = $x"
"`$y = $y"

$x * $y

}

PS> pc -x 2 -y 3
$x = 2
$y = 3
6

PS> pc 2 -y 3
$x = 2
$y = 3
6

PS> pc 2 3
pc : A positional parameter cannot be found that accepts argument '3'.
At line:1 char:1
+ pc 2 3
+ ~~~~~~
+ CategoryInfo : InvalidArgument: (:) [pc], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,pc

PS> pc -x 2 3
pc : A positional parameter cannot be found that accepts argument '3'.
At line:1 char:1
+ pc -x 2 3
+ ~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [pc], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,pc

 

So far it looks as position 0 or position 1 can be used as the first assigned position. What happens if we use both:

function pd {
param (

[Parameter(Position=0)]
[int] $x,

[Parameter(Position=1)]
[int] $y
)

"`$x = $x"
"`$y = $y"

$x * $y

}

PS> pd -x 2 -y 3
$x = 2
$y = 3
6

PS> pd 2 -y 3
$x = 2
$y = 3
6

PS> pd 2 3
$x = 2
$y = 3
6

 

So position 0 takes precedence over position 1

What if we have gaps in the position order:

function pe {
param (

[Parameter(Position=0)]
[int] $x,

[Parameter(Position=2)]
[int] $y
)

"`$x = $x"
"`$y = $y"

$x * $y

}

PS> pe -x 2 -y 3
$x = 2
$y = 3
6

PS> pe 2 -y 3
$x = 2
$y = 3
6

PS> pe 2 3
$x = 2
$y = 3
6

 

Numerical position order is used.

In the next case position 1 is assigned to the first parameter

function pf {
param (

[Parameter(Position=1)]
[int] $x,

[Parameter(Position=2)]
[int] $y
)

"`$x = $x"
"`$y = $y"

$x * $y

}

PS> pf -x 2 -y 3
$x = 2
$y = 3
6

PS> pf 2 -y 3
$x = 2
$y = 3
6

PS> pf 2 3
$x = 2
$y = 3
6

 

Note the order of positions

function pg {
param (

[Parameter(Position=2)]
[int] $x,

[Parameter(Position=1)]
[int] $y
)

"`$x = $x"
"`$y = $y"

$x * $y

}

PS> pg -x 2 -y 3
$x = 2
$y = 3
6

PS> pg 2 -y 3
$x = 2
$y = 3
6

PS> pg 2 3
$x = 3
$y = 2
6

 

x is assigned the first positional parameter because y is explicitly defined.

In the next case no parameter is given position 0 or 1

function ph {
param (

[Parameter(Position=4)]
[int] $x,

[Parameter(Position=2)]
[int] $y
)

"`$x = $x"
"`$y = $y"

$x * $y

}

PS> ph -x 2 -y 3
$x = 2
$y = 3
6

PS> ph 2 -y 3
$x = 2
$y = 3
6

PS> ph 2 3
$x = 3
$y = 2
6

PS> ph -x 2 3
$x = 2
$y = 3
6

 

When y is defined then x gets the first available positional value. When both x and y aren’t defined y gets the first positional parameter.

 

From the above.

Positional parameters are assigned a numeric position.

Defined parameters explicitly overrides positional order

Values are assigned in order of position

If a parameter isn’t defined it gets a value based on its position

Position ranking can start at any number – 0 and 1 are the defaults.

Lowest ranked undefined parameter gets the first positional value