31
Usnadně te si práci silně typovaným kódem a statickou analý zou! Ondř ej Mirtes

Ondřej Mirtes: Usnadněte si práci silně typovaným kódem a statickou analýzou!

  • Upload
    develcz

  • View
    220

  • Download
    4

Embed Size (px)

Citation preview

Usnadněte si prácisilně typovaným kódem 💪a statickou analýzou! 🔎

Ondřej Mirtes

100 %

Code coverage

Jedinýdnesuznávanýzpůsob,jakmítspolehlivouaplikacibezchyb,je100%pokrytítesty.Žádnáreálnáaplikacetoovšemnesplňujeasnažitseo100%aninemáekonomickýsmysl.

Business logika

Wiring

* nezměřeno vědeckou metodou

Jakztohoven?Nevšechnyzdrojákyjsousirovnyaněcosevyplatítestovatvícaněcomíň.Jákódrozdělujinabusinesslogiku,kteroujedůležitétestovat,awiring(kteréhojevaplikacinadpolovičnívětšina*),kdetestynepotřebujemeaspolehlivostzajistímejinak.

Wiring=boilerplate.Controllery,fasády,vytahovánívýsledkůapřeposíláníjinam-domodelu,došablony.Gettery,settery,přiřazovánídoproperties.Čímsložitějšíarchitektura,tímvícewiringu.

Businesslogika=todůležité,coaplikacedělá.Omezeníhodnot,validace,filtrováníařazení,parsování,počítání,zaokrouhlování.Mělobynanijítpsátrychléunittesty.

Wiringsedátotižzažitýmipostupytestovatpouzeintegračně.Integračnítestyjsoupomalé,křehkéaneradjepíšu.Pokudbychomnawiringpsaliunittesty,takbychommuselipsátspoustumockůatotakyneníideální.Testysealeuwiringudajínahraditpořádnýmitypy.

Stringly–typed code

function foo(string $id, string $name, string $email, string $directory, string $filename, string $address, string $price, string $date ) { }

Pokudněkdonepíšesilnětypovanýkód,taktovypadánějaktakhle.Všechnojestring,případnějinéskalárnítypy.Pokudsiodmyslímetypehintyúplně,můženámvšudedorazitnull,cožznamenádalšíkontrolyamožnéchybynavíc.

Strongly–typed codefunction foo( Email $email, SplFileInfo $directory, Address $address, Money $price, DateTimeImmutable $date): FooBar { }

Coznamenápoužívatsilnétypy?Využívatnavšechnoconejpřesnějšítyp,objekt.Cotímzískám?Správnýobjektmůževzniknoutjediněkonzistentníazvalidovaný.Typehintemříkám,cojedinělzedometodypředat.Avneposlednířadě,vím,codanýobjektdokáže,pohledemnajehometody.Anezapomeňmenaconejpřesnějšíreturntypehinty.

Stringly–typed code

$container->get('fooService')->doFoo();

Zastringy-typedkódnepovažujipouzereprezentacivšehojakostringů,alejakékoliodkazovánínazákladěmagickýchstringů.Ažpřiběhuprogramumůžuzjistit,žepožadovanáservisaneexistuje.

Strongly–typed code

/** @var FooService */private $fooService;

$this->fooService->doFoo();

Mnohemlepšíjevyžádatsiservisupřeskonstruktorstypehintem,čímžzajistímainformujivývojáře/IDE/statickýanalyzátorotom,covdanémparametruapropertyje.ProtorádpoužívámDIivcontrollerech,protožesepřikompilacikontejnerudozvím,jestlijevšeOK.

Nadužívání polí

function foo(array $values) { … $values['name'] … }

Spořádnýmitypehintynelzemetoduzavolatšpatně,alevpolivždymůžechybětdůležitýklíč.Atakynevímetypyhodnotjednotlivýchklíčů(pokudsemezisebouliší).

Pole jako seznam hodnot ✅

/** * @param User[] $users */ function foo(array $users) { foreach ($users as $user) { } }

Použítpolejakokolekcihodnotstejnéhotypu,nadkterouiteruji,jevpořádku.Vtétoukázcesimohubýtjistýtím,cobudev$user.

"Umím zpracovat cokoli"/** * @param array|string $values */ function foo($values) { if (is_array($values)) { … } else { … } }

Metoda,copřijímávícerůznýchtypů,znamená,žemusímenapsatif-složitějšíkód,vícevětvíktestování.

function foo(array $values) { … }

function bar(string $value) { … }

"Umím zpracovat jeden typ"

Přitommůžemenapsatdvěfunkce,kterépřijímajíkonkrétnítypazkaždéhomístazavolattusprávnou.Tosaméplatípronávratovétypy-vždyvracetjedenkonkrétnítyp.

Boolean parameteryfunction foo($values, bool $force) { if ($force) { … } else { … } }

Booleanparametrvětšinouznamená,žemetodadělátrochuněcojiného.Opětznamenánapsatifavícevětvíktestování.

Boolean parametery

foo([1, 2, 3], false); foo([1, 2, 3], true);

foo([1, 2, 3]); forceFoo([1, 2, 3]);

Rozdělení na více metod

Správnéřešenínamístobooleanparametrujeopětrozdělitnavícemetodazrůznýchmístzavolattusprávnou,copotřebuji.

Nullable parametry

function foo($a = null, $b = null, $c = null, $d = null, $e = null, $f = null, $g = null ) { }

Umetodsvětšímmnožstvímnullablečinepovinnýchargumentůvětšinouplatíjenněkterékombinace,např.prvnítřiparametrynenulovéspoluapod.Tonenínijakzanesenédotypovéhosystémuanavíctytokombinaceobvyklevyjadřujírůznéusecasy.Řešení-rozdělenínavícemetodbeznullableparametrů.Výsledek-mnohemrobustnějšíkód.

function foo( string $country, string $currency, string $errorCode )

Výčty – enumy

Pokudnějakýparametrpřijímáomezenýoborhodnot,kterýjepevnědanývkóduaplikace,použitískalárníchtypůnenívhodné,protožehodnotunijakneomezují.

Výčty – enumy

github.com/consistence/consistence

function foo( Country $country, Currency $currency, ErrorCode $errorCode )

Reprezentujtevýčtypomocíobjektů,např.skrzeknihovnuConsistence.Vyjádřítetím,covolajícímusídometodypředat,azajistítevaliditupředanéhodnoty.

ControllerWeak

HTTP request

Strong

ModelControllerHTTP response

Pokudnechátetypyprorůstvašíaplikací,budeceládalekospolehlivější,protožebudeteconejmíňvěcímít"mixed".Typyjsouidůvod,pročrádpoužívámORM.

Zpětná vazba od typů

Nevhodné interfaces

Naimplementovatinterfaceaupůlkymetodvyhazovatvýjimku-porušeníBarbaryLiskov,nevhodnýinterface.Musímenaslouchat,jakýnámkóddáváfeedbackonašichtypech.Pořádnýtypovýsystémjenemilosrdnějšínežtesty,hodnotí,covšelzeněkampředat,nejento,jakévstupyjsmeotestovali.

Zpětná vazba od typů

Využívání informace, která není v typech

Pokudněconenízanesenédotypůajendíkypředchozíkontrolečiproprietárnímznalostemvím,žemizvolanémetodypřijdenějakákonkrétnítřída,kteránenívtypehintu.

Statická analýza 🔎

Statickýanalýzahledáchybyvkódu,anižbyhospouštěla,pouzezkoumánímzdrojáků.Zkontroluje,žeaplikacenespadnenaněčemnedefinovaném,ževšudepředávámsprávnétypy,ževracím,cojsemslíbilatd.

composer require --dev phpstan/phpstan

github.com/phpstan/phpstan

První spuštění

• Parse errory • Třídy, které nejdou vůbec načíst • Špatně nastavený autoloading

Projekt,kterýjejižnějakoudobuvyvíjenbezstatickéanalýzy,naakumulujesoubory,kterétřebaaninejdounačíst,takžesenedivte,kdyžtakovéPHPStanuvásnajde.

Levely v PHPStanu

$%&'()

Abychomezilmnožstvíchyb,kteréPHPStanponainstalovánízačnehlásit,zavedljsemumělélevely.Začnětehopoužívatnalevelu0aopravtetěchpárchyb,abystemělizelenýbuild.Aažbudetemítpříštěčas,navyštelevelaopravtedalšíchyby.

if ($foo instanceof Foo)

catch (FooException $e)

Foo::class

function foo(Bar $bar)

PHPsamotnémunevadí,pokudsevtěchtopřípadechodkazujetenaneexistujícítřídy.PHPStantakovépřípadynajdeadonutívásjeopravit.

Foo::NONEXISTENT_CONSTANT

Foo::$nonexistentProperty

$this->nonexistentProperty

$this->nonexistentMethod()

nonexistentFunction()

Na vyšších levelech• Nejen na $this

• Předávané typy, nejen počty • Návratové hodnoty • Nedefinované proměnné • …a řada dalších kontrol

PHPStannalevelu0hledáchybynastatickýchvoláníchana$this.Tamsimůžebýtjistýtypem.Navyššíchlevelechhledáchybynavšem,aleužpřitommusíčístaspoléhatsenaphpDocy,vekterýchmůžebýttakéchyba,kterouvámochotněnahlásí.

vs. PHPStan?

PročpoužívatPHPStan,kdyžmámPhpStorm?PHPStanbysteměliintegrovatapouštětvrámciCIbuildu(Travis,TeamCity,Jenkins,GitLabCI…).NevšichnivývojářipoužívajíPhpStormamajíhostejněnakonfigurovaný,anevšimnousikaždéchyby,coIDEpodtrhne.

youtu.be/h5jC7l0-jRI 👉

ProvíceinformacíoPHPStanu,covšechnoumíajakémožnostikonfiguracearozšířenískýtá,mrknětenazáznamzPoslednísoboty.

phpstan/phpstan

@OndrejMirtes

ondrej.mirtes.cz