OneLiner nie jest skryptem

pasqdny dzień. migrena, potem gorączka, a jak mam gorączkę to muszę coś napisać. czasem głupoty, ale dziś może coś sensownego. i pisząc skrypt wstrzyqjący stopki dla OWA i mobile w EXO dla paru tysięcy userów, pomyślałem o tym czemu z OneLinera zrobiło się ponad 4oo linii kodu w dwóch skryptach. nie wszyscy to rozumieją, a jeśli ktoś skrypty pisać musi, lub lubi, to powinien to bardzo dobrze (z)rozumieć. dla tego wpis, poświęcony klepaczom kodu, którzy chcą robić to lepiej.

pisanie skryptów to praca dość niewdzięczna i mało opłacalna. kiedyś sądziłem, że jak powymiatam w pisaniu PS to będę mógł na tym sensownie zarobić. fakty są takie, że za skrypty rzadko ktoś chce płacić. „bo przecież to jedno polecenie”, albo że tego się nie da używać. no i w sumie… muszę się zgodzić. skrypty na zlecenie zdarzają się, ale rzadko.

w zasadzie robię już trochę inne rzeczy, ale czasem wspieram 2gą i 3cią linię. PowerShell to moje hobby, ale w pracy oczywiście czasem się przydaje. skrypty rzadko bo:

  • 1sza linia wsparcia boi się literek. jak coś nie ma GUI, to jest nie-do-użycia. nie ma znaczenia czy jest dokumentacja, i czy to w ogóle robi coś skomplikowanego, ale klawiatura dla pierwszej linii służy do logowania. też pewnie już niedługo, bo będą się logować biometrią a w dużej mierze zostaną zastąpieni chatbotami. a więc pisanie automatyzacji w postaci skryptu dla nich – nie ma sensu.
  • 2ga linia wsparcia owszem, uruchomi skrypt. ale jeśli coś się wysypie, pokaże się jakiś błąd… koniec. skrypt do śmieci, strach, nie chcemy. oczywiście tutaj jest już sporo wyjątqw, osób które po prostu *potrzebują* automatyzacji, więc się uczą. a czasem nawet lubią.
  • 3cia linia wsparcia… jest nieliczna i dość samowystarczalna. ale zazwyczaj wolą zassać jakiś skrypt z netu a potem szukać 1oo łorkeraundów jak go użyć do swoich potrzeb, niż coś napisać. ludzie wiedzą jak 'coś osiągnąć’ – ale napisanie skryptu to inna para kaloszy.

to oczywiście subiektywna ocena, na podstawie doświadczeń własnych. wniosek jednak nasuwa się prosty – chcesz zarobić na kodowaniu, to weź się za coś, co ma interfejs, bo linia poleceń nadal straszy. jest dla nerdów, geeków i popraprańców. ewentualnie – ostatnia deska ratunq.

OneLiner nie jest skryptem. jest… łanlajnerem. nie będę wchodził w filozoficzno-semantyczne dywagacje i definicje – dla mnie nie jest to skrypt. zastosowanie onelinera jest wtedy, kiedy robi się coś bieżącego, trzeba zrobić raz i na szybko, i samemu kontroluje się przebieg. zazwyczaj to tylko jeden w wielu kroqw w długiej pracy. skrypt dla odmiany – to coś co pisze się, żeby było. żeby zostało i żeby można było tego użyć wiele razy i wielu warunkach… a co najważniejsze – żeby użyć tego mogli inni.

taka jest moja definicja.

to samo inaczej

dostałem skrypt mailem – nawet nie oneliner, miał ponad 1oo linii kodu. i prośba „weź tu tylko braqje takiego dyngsa i już. easypeasy… aaa i to ma być uruchamiane przez adminów potem”. oj. czyli celem nie jest to, co robi skrypt, tylko automatyzacja powtarzalnego zadania, przez osoby z 2giej linii. to zmienia wszystko.

zajrzałem do środka – jak na robotę admina, spoko. co prawda z 'dyngsem’ by sobie nie poradził i zrobił zapętloną enumerację – czyli wydłużył przebieg do kwadratu, co przy tysiącach elementów i przebiegu w okolicy 3-4h, nagle zrobiłoby się 3-4 dni (; … ale widać, że ogólnie ogarnia. a jak zatem powinien wyglądać skrypt 'dla kogoś’, dla 2giej linii? kilka wskazówek:

  • włącz cmdletbinding – proste, a daje dodatkowe możliwości np. tryb verbose i pełną obsługę parametrów.
  • zrób dobre opisy! wykorzystaj to, co daje PS i dobrze udoqmentuj skrypt. przyda się zarówno innym jak i Tobie
  • nie nadawaj nazw zmiennych typu '$a’ czy '$tmp’ – każdy normalny edytor ma intellisense, więc nie bój się wpisać '$tymczasowyImportDanych’ – przecież edytor to sam dokończy, a kod staje się czytelniejszy
  • jeśli niezbędny jest import danych – musisz założyć, że ktoś zamiast pliq tekstowego spróbuje załadować obrazek, że csv będzie miał złe kolumny albo że ktoś w ogóle go ominie. weryfikacja danych jest jednym z najpracochłonniejszych elementów – a ludzie są leniwi. dobra weryfikacja danych wejściowych to mniej błędów
  • OBSŁUGA BŁĘDÓW. to jedna z najtrudniejszych rzeczy – nie tylko przy skryptach. ale w przypadq skryptów, istnieje przesąd, że obsługa błędów jest niepotrzebna albo że w ogóle jej nie ma. jeśli oddajesz skrypt komuś, to niemal każda operacja powinna być otoczona try/catch lub weryfikacją zmiennej wyjściowej działania. inaczej skrypt będzie się sypał i nikt nie będzie widział czemu, albo nawet, że się sypie. to powoduje, że kod puchnie niebotycznie bo zamiast jednej, prostej linijki nagle robi się dziesięć, ale bez tego będzie scenariusz: nie zadziałało, nie wiem, boję się, kasuję.

oczywiście takich przykazań można by mnożyć i wypisywać przez pół nocy, ale wybrałem te, których zazwyczaj nie znajduję nawet w skryptach zassanych z technet/codeplex/github czy innych repo – teoretycznie stworzonych do konsumpcji przez innych. tak jak zasadą House MD dla wsparcia jest 'użytkownik zawsze kłamie’, tak dla skypciarzy (a w zasadzie i w ogóle ogólnie) jest 'ludzie są leniwi’. robią minimum. chcesz napisać skrypt dobrze – napisz tak, jak byś sam chciał go użyć, pierwszy raz go widząc, nie bądź leniwy.

przykładowy szkielet skryptu, który może posłużyć jako szablon:

<#
.SYNOPSIS
    skrypt ogólnie robi to i tamto
.DESCRIPTION
    tutaj już pełna instrukcja co i jak, w jaki sposób przygotować dane. jakie są warunki działania, kiedy sie może 
    wywalić, i wszystko inne, co w skrócie nazywa się 'dokumnetacją'
.EXAMPLE 
    .\set-ExampleSctipt.ps1
    dodaj informacje jak skrypt odpalić 
.EXAMPLE 
    .\set-ExampleSctipt.ps1 -dataFile abc.txt -param2 3
    nie szczędź przykładów i opisów! jeśli sam zaczynasz korzystać z czegoś, czego nie znasz, to pomaga
.INPUTS
    plik txt - płaski plik zawierające dane oddzielone enterem. to pedanteria, ale warto dodać 
.OUTPUTS
    ten skrypt nie ma outputu - ale warto to napisać
.NOTES
    nExoR ::))o-
    ver.20190716
    20190716 warto trzymać sobie wersję. nawet jeśli trzymasz repo na GitHubie - warto mieć loga z inormacją o zmianach
    20190715 w końcu ktoś dostaje nową wersję - chciałby wiedzieć co się zmieniło. nie robisz tego tylko dla siebie. 
    20180101 ...ty po roku też nie będziesz pamiętał
#>

[cmdletbinding()]
param (
    [parameter(Mandatory=$false,position=0)]
        [string]$dataFile,
    #zrób opis po co jest parametr - tutaj będzie to import danych
    [parameter(Mandatory=$false,position=1)]
        [string]$param2,
    #tutaj co prawda głupie param - ale nie bój się nadawać nazw parametrów, które przedstawiają ich znaczenie
    [parameter(Mandatory=$false,position=2)]
        [string]$logFile="_set_example-$(Get-Date -Format yyMMddHHmm).log"
    #dobre logowanie jest super ważne! jak potem sprawdzisz co zadziałało a co nie? 
)

#logowanie warto zrobić do pliq i opcjonalnie - na ekran. dla tego zawsze korzystam 
#z funkcji która mi to forqje na oba wyjścia
function write-log {
    param(
        [string]$text
    )
    if($text -match '\[WRN\]') {
        write-host -ForegroundColor Magenta $text
    } elseif ($text -match '\[ERR\]') {
        write-host -ForegroundColor Red $text
    } else {
        write-verbose $text
    }
    $text|out-file $LogFile -Append
}

$someData= Import-Csv $dataFile -Delimiter $delimiter -Encoding Default
#weryfikacja poprawności csv dla pliku danych - czy na pewno to taki plik, jaki sie oczeqje?
$expectedHeader=@("kolumna 1","innakolumna")
$csvHeader=$someData|get-Member -MemberType NoteProperty|select-object -ExpandProperty Name 
$missingColumn=@()
foreach($headElement in $expectedHeader) {
    if($csvHeader -notcontains $headElement) {
        Write-log "[ERR] brakuje kolumny $headElement w pliku $dataFile"
        $missingColumn+=$headElement
    }
}
if($missingColumn) {
    write-log -text "[ERR] nieprawidłowy format pliku wsadowego"
    exit -3
}

$data=import-csv -delimiter ';' $dataFile

$data

$VerbosePreference = "continue"
write-log -text "done."

nie ma tu żadnego try/catch… ale jest przykład jak obsłużyć dane wejściowe i nie oszczędzać na opisach i nazwach parametrów.

jedni biegają albo chodzą na imprezy, ja sobie skrobię skrypty (; a jeśli chcesz programować zawodowo – to raczej sięgnij po VS i zacznij ogarniać jakieś .NETy, pytongi czy inne duże frameworki.

gorączka spadła, czas usnąć. miłego kodowania!

eN.

PS. contains nie jest tym, czym się wydaje.

-o((:: sprEad the l0ve ::))o-

Comments (3)

  1. Odpowiedz
    • Odpowiedz

      faktycznie konkluzje bardzo podobne (:
      fajne arty! warte polecenia tym co się uczą. dzięki za linki

  2. mateusz

    Odpowiedz

    Świetny wpis. Ze swojej strony dodam, że admin, który nigdy nie pisał własnych skryptów jest tylko operatorem.

Skomentuj nExoR Anuluj pisanie odpowiedzi

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Time limit is exhausted. Please reload CAPTCHA.