Kodėl apskritai rūpintis kodo stiliumi?
Kai pradedi programuoti Python, greičiausiai pirmiausia rūpiniesi, ar kodas veikia. Ar funkcija grąžina teisingą rezultatą? Ar programa nesugriūva? Tai visiškai normalu. Bet kai pradedi dirbti komandoje arba grįžti prie savo kodo po kelių mėnesių, staiga supranti, kad kodo skaitomumas yra ne mažiau svarbus nei jo funkcionalumas.
Python bendruomenė turi PEP 8 – tai oficialus stiliaus vadovas, kuriame aprašyta, kaip turėtų atrodyti geras Python kodas. Tačiau problema ta, kad rankiniu būdu laikytis visų šių taisyklių yra varginantis darbas. Ar po kablelio turėtų būti tarpas? Kiek tuščių eilučių turėtų būti tarp funkcijų? Ar šita eilutė per ilga? Ir čia į sceną įžengė Black formatter.
Black save vadina „nekompromisiniu kodo formatuotojas”. Skamba šiek tiek agresyviai, tiesa? Bet būtent tai ir yra jo stiprybė – jis priima sprendimus už tave, ir tau nereikia galvoti apie formatavimą. Tiesiog paleidi Black, ir tavo kodas tampa nuoseklus, skaitomas ir atitinkantis bendruomenės standartus.
Kas yra Black ir kuo jis skiriasi nuo kitų įrankių?
Black nėra vienintelis Python kodo formatavimo įrankis. Yra autopep8, yapf ir kiti. Tačiau Black turi vieną esminį skirtumą – jis beveik neturi konfigūracijos galimybių. Tai gali skambėti kaip trūkumas, bet iš tikrųjų tai yra didžiulis privalumas.
Kai naudoji įrankį su daugybe nustatymų, komandoje prasideda diskusijos: „Gal geriau naudoti viengubus kabutes?” „O gal dvigubus?” „Kiek tarpų turėtų būti įtrauka?” Su Black tokių diskusijų nėra. Jis formatuoja kodą vienaip, ir visi sutinka. Taip sutaupi daug laiko ir nervų.
Black naudoja 88 simbolių eilutės ilgį pagal nutylėjimą (o ne 79, kaip rekomenduoja PEP 8). Kodėl? Kūrėjai teigia, kad tai geriau tinka šiuolaikiniams ekranams ir leidžia rašyti šiek tiek kompaktiškesnį kodą. Tai vienas iš nedaugelio dalykų, kuriuos galima pakeisti, bet daugelis tiesiog naudoja numatytuosius nustatymus.
Kaip įdiegti ir pradėti naudoti Black
Įdiegti Black yra paprasta kaip ir bet kurią kitą Python biblioteką. Tiesiog atidari terminalą ir įveši:
pip install black
Jei naudoji virtualią aplinką (o turėtum), įsitikink, kad ji aktyvuota prieš diegdamas. Kai Black įdiegtas, galima jį iškart naudoti. Paprasčiausias būdas – nurodyti failą arba katalogą:
black mano_failas.py
arba
black mano_projektas/
Black peržiūrės visus Python failus ir juos suformatuos. Jei nori tik pamatyti, ką Black pakeistų, bet dar nekeisti failų, naudok --check vėliavėlę:
black --check mano_projektas/
O jei nori matyti, kokie būtų pakeitimai, naudok --diff:
black --diff mano_projektas/
Tai labai naudinga, kai tik pradedi naudoti Black esamame projekte ir nori suprasti, kiek daug jis pakeis.
Integravimas į darbo procesą
Vienas dalykas – paleisti Black rankiniu būdu, visai kitas – integruoti jį į savo kasdienį darbo procesą. Yra keletas būdų, kaip tai padaryti, ir geriausia naudoti kelis iš karto.
Pirma, galima sukonfigūruoti savo kodo redaktorių, kad jis automatiškai paleistų Black kiekvieną kartą išsaugant failą. VS Code tai padaroma įdiegus Python plėtinį ir nustatant python.formatting.provider į „black”. PyCharm taip pat palaiko Black kaip išorinį įrankį. Tai labai patogu – rašai kodą, spaudžiai Ctrl+S, ir jis automatiškai suformatuojamas.
Antra, galima naudoti pre-commit hook’us. Tai skriptai, kurie automatiškai paleidžiami prieš darant commit į Git. Įdiegus pre-commit biblioteką ir sukonfigūravus Black, tavo kodas bus automatiškai formatuojamas prieš kiekvieną commit. Tai užtikrina, kad į repozitoriją patektų tik tinkamai suformatuotas kodas.
Trečia, galima pridėti Black patikrinimą į CI/CD pipeline. Pavyzdžiui, GitHub Actions gali paleisti Black su --check vėliavėle, ir jei kodas nėra tinkamai suformatuotas, build’as nepraeis. Tai ypač naudinga dirbant komandoje – niekas negali įkelti nesuformatuoto kodo.
Ką Black iš tikrųjų daro su tavo kodu
Pažiūrėkime į konkrečius pavyzdžius. Tarkime, turime tokį kodą:
def skaiciuoti_suma(sarasas):
rezultatas=0
for skaicius in sarasas:
if skaicius>0:
rezultatas+=skaicius
return rezultatas
Žmogui skaityti tai nėra baisu, bet neatitinka PEP 8 standartų. Black jį performatuos taip:
def skaiciuoti_suma(sarasas):
rezultatas = 0
for skaicius in sarasas:
if skaicius > 0:
rezultatas += skaicius
return rezultatas
Matai skirtumus? Pridėti tarpai aplink operatorius. Tai gali atrodyti kaip smulkmena, bet kai skaitai šimtus eilučių kodo, tokie dalykai labai padeda.
Black taip pat tvarko ilgas eilutes. Jei turi tokį kodą:
labai_ilgas_funkcijos_pavadinimas(pirmas_argumentas, antras_argumentas, trecias_argumentas, ketvirtas_argumentas, penktas_argumentas)
Black jį perskirs į kelias eilutes:
labai_ilgas_funkcijos_pavadinimas(
pirmas_argumentas,
antras_argumentas,
trecias_argumentas,
ketvirtas_argumentas,
penktas_argumentas,
)
Atkreipk dėmesį į kablelį po paskutinio argumento – tai Black stilius, ir jis iš tikrųjų naudingas, nes leidžia lengviau pridėti naujus argumentus ateityje.
Konfigūracijos galimybės (nors jų ir nedaug)
Nors Black save vadina nekompromisiniu, yra keletas dalykų, kuriuos galima konfigūruoti. Dažniausiai tai daroma per pyproject.toml failą projekto šakniniame kataloge.
Štai pavyzdys:
[tool.black]
line-length = 100
target-version = ['py38', 'py39']
include = '\.pyi?$'
extend-exclude = '''
/(
| migrations
| \.venv
)/
'''
Čia nurodome, kad eilutės ilgis gali būti iki 100 simbolių (vietoj numatytųjų 88), kad taikome Python 3.8 ir 3.9 versijoms, ir kad norime ignoruoti migrations katalogą bei virtualią aplinką.
Tiesą sakant, daugelis projektų naudoja numatytuosius nustatymus ir keičia tik line-length, jei apskritai keičia. Tai ir yra Black filosofija – mažiau pasirinkimų, daugiau nuoseklumo.
Darbas su komanda ir esamais projektais
Vienas iš didžiausių iššūkių pradedant naudoti Black – tai pritaikymas esamam projektui. Jei projektas didelis ir turi daug kodo, Black gali pakeisti tūkstančius eilučių. Tai sukels milžinišką diff’ą, ir bus sunku peržiūrėti kitus pakeitimus tame pačiame pull request’e.
Geriausia strategija – padaryti atskirą commit’ą arba net atskirą pull request’ą tik Black formatavimui. Pavadink jį kažkaip aiškiai, pavyzdžiui, „Apply Black formatting to entire codebase”. Taip kiti komandos nariai žinos, kad šis commit’as tik formatavimas ir nereikia jo atidžiai peržiūrėti.
Dar vienas patarimas – susitark su komanda iš anksto. Jei staiga pradėsi formatuoti visą kodą Black’u, o kiti komandos nariai nežinos, gali kilti konfliktų. Geriau aptarti tai komandos susitikime, paaiškinti privalumus ir susitarti dėl perėjimo plano.
Kai kurie žmonės iš pradžių priešinasi Black, nes jis pakeičia jų įprastą kodo stilių. Bet po kelių savaičių dauguma pripažįsta, kad nebereikia galvoti apie formatavimą – tai labai atlaisvina protą kitiems dalykams.
Black ir kiti kodo kokybės įrankiai
Black yra tik vienas iš daugelio įrankių, kurie padeda palaikyti kodo kokybę. Jis puikiai dera su kitais populiariais įrankiais:
**Flake8** – tai linter’is, kuris tikrina kodo klaidas ir stiliaus pažeidimus. Black rūpinasi formatavimo, o Flake8 gali rasti loginių klaidų, nenaudojamų kintamųjų ir panašiai. Naudojant juos kartu, reikia šiek tiek konfigūruoti Flake8, kad jis neprikaibinėtų prie Black stiliaus pasirinkimų.
**isort** – tai įrankis, kuris tvarko import’ų tvarką. Black netvarkys tavo import’ų, todėl isort yra puikus papildymas. Beje, isort turi Black profilį, kurį galima įjungti, kad abu įrankiai gerai dirbtų kartu.
**mypy** – tai statinio tipo tikrinimo įrankis. Jis visiškai neprieštarauja Black ir puikiai veikia kartu. Mypy tikrina tipus, Black formatuoja kodą – skirtingos atsakomybės.
**pylint** – dar vienas linter’is, kuris yra griežtesnis už Flake8. Kai kurie žmonės naudoja pylint vietoj Flake8, kiti naudoja abu. Su Black jis taip pat gerai dera, nors gali reikėti šiek tiek konfigūracijos.
Gera praktika – naudoti visus šiuos įrankius kartu. Black pasirūpina formatavimo, linter’iai randa potencialias klaidas, isort tvarko import’us, o mypy tikrina tipus. Kartu jie sukuria stiprią kodo kokybės gynybos liniją.
Kai Black tau nepatinka (ir ką su tuo daryti)
Būkime sąžiningi – ne visiems patinka, kaip Black formatuoja kodą. Kai kurie žmonės nekenčia kablelio po paskutinio elemento sąrašuose. Kitiems nepatinka, kaip jis skaido ilgas eilutes. Dar kitiems tiesiog nepatinka, kad įrankis priima sprendimus už juos.
Jei esi vienišas programuotojas ir dirbi tik su savo projektais, gali naudoti bet kokį stilių, kokį nori. Bet jei dirbi komandoje arba kuri open source projektą, nuoseklumas yra svarbesnis už asmeninius stilistinius pasirinkimus.
Vienas dalykas, kurį galima daryti – naudoti # fmt: off ir # fmt: on komentarus, kad Black ignoruotų tam tikras kodo dalis. Pavyzdžiui:
# fmt: off
matrica = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
# fmt: on
Čia norime, kad skaičiai būtų lygiuoti stulpeliais, o Black norėtų pašalinti tuos papildomus tarpus. Komentarai liepia Black neliesti šios dalies.
Bet naudok tai taupiai. Jei randi save rašantį # fmt: off kas kelias eilutes, galbūt Black nėra tau. O gal tiesiog reikia laiko priprasti prie naujo stiliaus.
Kodėl Black tampa standartu Python bendruomenėje
Per pastaruosius kelerius metus Black tapo de facto standartu daugelyje Python projektų. Jei pažiūrėsi į populiarius open source projektus GitHub’e, vis dažniau rasi juos naudojančius Black.
Priežastis paprasta – jis išsprendžia problemą, kuri varginusi Python bendruomenę ilgus metus. Kiekvienas projektas turėjo savo stiliaus vadovą, kiekvienas programuotojas turėjo savo nuomonę, kaip turėtų atrodyti kodas. Tai sukeldavo begalines diskusijas pull request’uose apie tarpus ir kabutes.
Black užbaigia šias diskusijas. Ne todėl, kad jo stilius būtų objektyviai geriausias (nėra tokio dalyko kaip objektyviai geriausias stilius), bet todėl, kad jis nuoseklus ir automatizuotas. Kai visi naudoja Black, visų kodas atrodo panašiai, ir galima sutelkti dėmesį į tai, kas iš tikrųjų svarbu – į kodo logiką ir funkcionalumą.
Dar vienas faktorius – dideli projektai pradėjo naudoti Black. Django, Flask, pytest ir kiti žinomi projektai perėjo prie Black. Kai matai, kad tokie projektai pasitiki Black, lengviau apsispręsti jį naudoti ir savo projektuose.
Praktiniai patarimai pradedantiesiems
Jei dar nenaudoji Black, bet nori pradėti, štai keletas patarimų, kaip tai padaryti sklandžiai:
**Pradėk nuo naujo projekto.** Jei tik pradedi naują projektą, įtraukti Black nuo pat pradžių yra lengviausia. Sukonfigūruok jį pirmame commit’e, ir viskas bus suformatuota nuo pat pradžių.
**Esamam projektui – darykite palaipsniui.** Jei projektas didelis, nebūtina formatuoti visko iš karto. Galima pradėti nuo naujai kuriamų failų arba nuo specifinio modulio. Nors tai sukuria nenuoseklumą trumpam laikui, ilgalaikėje perspektyvoje tai gali būti lengviau priimtina komandai.
**Naudok pre-commit hook’us.** Tai užtikrins, kad naujas kodas visada bus suformatuotas. Net jei pamiršti paleisti Black rankiniu būdu, hook’as tai padarys už tave prieš commit’ą.
**Integruok į CI/CD.** Pridėk Black patikrinimą į savo continuous integration pipeline. Tai užtikrins, kad į main šaką pateks tik tinkamai suformatuotas kodas.
**Dokumentuok savo projekto README.** Parašyk, kad projektas naudoja Black, ir kaip jį paleisti. Tai padės naujiems kontributoriams greitai prisitaikyti.
**Būk kantrus su komanda.** Jei dirbi komandoje, suprask, kad kai kuriems žmonėms reikės laiko priprasti. Paaiškink privalumus, parodyk, kaip Black sutaupo laiko, ir leisk žmonėms išsakyti savo nuogąstavimus.
Ateitis su Black ir be galvos skausmo
Formatavimas niekada neturėtų būti didžiausia tavo problema programuojant. Yra daug svarbesnių dalykų, į kuriuos reikia sutelkti dėmesį – architektūra, testavimas, našumas, saugumas. Black leidžia tau rūpintis šiais dalykais, o ne tuo, kiek tarpų turėtų būti po kablelio.
Kai pradedi naudoti Black, pirmąsias kelias dienas gali jaustis keistai. Kodas gali atrodyti „ne taip”, kaip įpratęs. Bet po savaitės ar dviejų tai tampa normalu. O po mėnesio jau negalvoji apie formatavimą – tiesiog rašai kodą, ir jis automatiškai tampa skaitomas ir nuoseklus.
Tai yra Black tikroji vertė – ne konkretus formatavimo stilius, kurį jis naudoja, bet tai, kad tu nebegaišti laiko galvodamas apie formatavimą. Tai viena mažiau problema, viena mažiau diskusija, vienas mažiau dalykas, dėl kurio reikia priimti sprendimą. Ir programavime, kur sprendimų reikia priimti šimtus kasdien, tai tikrai sveikintina.
Jei dar nenaudoji Black, išbandyk jį. Įdiegk, paleisk savo projekte, pažiūrėk, ką jis daro. Galbūt tau patiks, galbūt ne. Bet bent jau suprasite, kodėl tiek daug Python programuotojų jį pasirinko. O jei jau naudoji – gal laikas įtikinti ir savo komandą?
