I saw, several times now, scripts were it is just a series of commands, sometime just created with copy/paste and few changes.
This is far from best practices in terms of readability, maintainability and debug (ability 🙂).

My Best Practices

Use functions (with types)

Beside adding, the most obvious re-usability, using functions also helps for code maintainability. For instance, if a bug is found and the fix is in a function used 10 times, you will have to fix it once and not 10 times. It also makes code readability better.

Manage errors

If the scripting language you are using support exception, catch exception and use them. It is important, like for example calling a WebService, to catch known and unexpected exception. For example, if an error code 500 (Internal Server Error) is raised while querying a WebService, the script will not be able to proceed any further and thus error code and message could be logged and script stopped.
Also, exception can make the code easier to maintain. Assuming that piece of code:

    Try {
        If ( $input -like 'ADM_*' ){
            # call function with parameters
            FUNCTION_A "ADM"
        } ElseIf ( $input -like 'SYS_*' ) {
            FUNCTION_A "SYS"
        } else
            return $false
        } # End If ADM user
    } Catch {
        # manage the exception as it failed
    }

Instead of managing errors in each If and ElseIf part, multiplying the effort, it is easier to throw an exception in FUNCTION_A that will be caught at end of If’s. With this, you can quick go out of execution stack up to the first catch encountered.

Debugging

For example, in my PowerShell scripts, I usually add this function:

Function Write-Log ([string] $log) {
    $date = Get-Date -Format "dd-MMM-yyyy HH:mm:ss.fff"
    If ($Global:debug) {
        $message = '{0} ({1} ms) - {2}' -f $date, ([math]::floor($measureTime.Elapsed.TotalMilliseconds)), $log
        $measureTime.Restart()
    } Else {
        $message = '{0} - {1}' -f $date, $log
    }
    Write-Host($message)
    $Global:StreamWriter.WriteLine($message)
} # End Write-Log

It nicely format log message with date and time and, if running in debug mode, also include time difference between each log messages. This message will be displayed in console and store in script log file. StreamWriter global variable is set at script initialization. This is the most efficient method I found to write into files.
Visual Studio Code is also not to neglect. It is developed by Microsoft, customizable via plugins and includes an excellent integrated debugger.

Use classes

In some cases, it could be interesting to use classes to hide complexity of certain object.
For example, I had the need to create an Excel report based on a WebService result. Instead of managing complexity of Excel in the main function, I created:

  • A class with a constructor that start Excel and initiate the new sheet
  • A method in this class to set the columns names and width
  • A method to append a line where current line number is maintained in the class

Comments your code

I am sometimes in a hurry and do not comment properly the code. This will probably lead to a waste of time if some changes of code have to be done several weeks of months later. If you don’t do it for others, do it for yourself.

Algorithm

Algorithm is an important part of coding leading to efficient (or not) scripts. Each case is different and the faster algorithm is not necessarily the first you will think of. Just look at sorting algorithm, quick sort being the fastest one.

And you?

This is a few rules or tips that I am trying to follow.
Do you have some others to share ?