O tom, ako sa nestratiť vo vlastnom kóde alebo ako neprísť o priateľov keď čítajú vaše zdrojáky. Aj v dobe objektov, tried a interfaceov je veľmi ľahké navariť z kódu kvalitné špagety. Zopár praktických tipov ako tomu predchádzať.
Vývoju softwaru sa venuje profesne cez 10 rokov, pracoval na mnohých pozíciách vo firmách ako ui42 či Piano Media. Momentálne vedie malú softwarovú firmu so zameraním na webový vývoj. V Prešove organizuje stretnutie WebElement (podobné WEBtlak-u) a podieľa sa na coworkingu Eastcubator Prešov. Rád hľadá jednoduché odpovede na jednoduché otázky a tým zložitým sa radšej vyhýba :)
7. Čo je to čistý kód?
Rovnaká
● rýchlosť vývoja
● kvalita
● bugovosť (nebugovosť)
● spokojnosť zadávateľa
● radosť programátora
Ako pri na začiatku vývoja
11. I don't know how
Prečo ne - písať čistý kód
● veď to funguje
● ale ja to predsa viem prečítať
● toto je kratšie / menej kódu
● ale toto je rýchlejšie
● nestíham !!!
● vštci sú LAMERI len ja som KÓDER
13. Čo je náš cieľ
● ZNÍŽIŤ WTF FAKTOR
● pochopiť zmysel kód
● orientovať sa v toku behu programu
● zmysluplne debugovať
● neodkladne zaznamenať a lokalizovať chybu
● riadiť error handling dev / production
● obmedziť ukladaniu nekonzistentných dát
● jednoduché pridávanie funkcionality
18. Naming convention
● nevytvárať tajné dohovory, ktoré nie je
možné vyčítať z kódu.
● maďarská notácia
○ sName, bAdmin, dPrice, cCustomer
● Capital pre objekty, atď ...
○ $User, $name, $user ???
● magic functions
○ $this->__call(), $this->__get()
not The Da Vinci Code
19. Princíp najmenšieho
prekvapenia
Názvy tried, funkcií a premenných
○ majú niesť význam toho, čo vykonávajú
○ nevykonávať to čo nenesú v názve
public function getName()
{
$this->deleteParent();
return $this->name;
}
22. DRO (Don't repeat others)
● pýtať sa
● komunikovať s kolegami
● checknúť zdrojáky!
● nebyť lenivý
● nepísať novú funkciu / classu ak sa dá stará
prispôsobiť
25. /** Komentáre **/
Komentár duplikuje názov funkcie
/**
* Add item decorator
*/
public function addItemDecorator(EshopDecoratorAbstract $decorator)
Komentár duplikuje názov volanej funkcie
// order is paid
if ($order->isPaid())
26. /** Komentáre **/
● Zakomentovaný kód
○ Vymazať – stále ostane v repozitároch
○ (svn, mercurial, git ... )
● Vtipné, injektívne odkazy kolegom
○ Vymazať ! – povedať pri káve, zavolať, poslať mail ...
//no need to save the object - it has not been changed
//DBOF::saveObjectFactory();
27. Funkcie
● funkcia má vykonávať len jednu vec
● mala by byť malá
● granulovať logické celky
● v jednej funkcii iba jedna podmienka
28. Funkcie - granulácia
public function newEventAction()
{
$this->form = new My_Form_Event_New();
$this->form->addCSRFProtection();
$this->view->event_form = $this->_form;
if ($this->_request->isPost())
{
$data = $this->_getAllParams();
if($this->form->isValid($data))
{
$values = $this->form->getValues();
$event = new Event($values);
$event->save();
}
}
}
29. Funkcie - granulácia
public function newEventAction()
{
$this->prepareForm();
if ($this->_request->isPost())
{
$this->submitForm();
}
}
30. Funkcie - granulácia
private function prepareForm()
{
$this->form = new My_Form_Event_New();
$this->form->addCSRFProtection();
$this->view->event_form = $this->form;
}
private function submitForm()
{
$data = $this->_getAllParams();
if($this->form->isValid($data))
{
$values = $this->form->getValues();
$event = new Event($values);
$event->save();
}
}
31. Funkcie - argumenty
● minimalizovať počet argumentov
● najlepší počet argumentov = 0
○ granulovať funkciu na samostatnú triedu
● settery a ”void” funkcie by mali vracať
inštanciu rodičovského objektu
public function sendMessage($message, $subject, $users_ids, $item_id, $item_type_id = null,
$template_id = null)
{
// do something
}
32. Funkcie - argumenty
class Message
{
public function setMessage($message)
{
$this->message = $message;
return $this;
}
public function setSubject($subject)
{
$this->subject = $subject;
return $this;
}
public function setReceiversIds($users_ids)
{
$this->users_ids = $user_ids;
return $this;
}
public function send()
{
// send message
}
}
34. Funkcie
logické argumenty porušujú základný
predpoklad
public function makeAdmin($bool = true)
{
$this->role = 'admin';
if ($bool == false)
{
$this->role = 'user';
}
$this->save();
}
public function makeAdmin()
{
$this->role = "admin";
return $this->save();
}
public function removeAdmin()
{
$this->role = "user";
return $this->save();
}
35. Funkcie - vstup -výstup
● Funkcia môže vracať iba hodnoty jedného
typu
● Pokiaľ neide o FACTORY
public function getUsers($sql = false)
{
$select = $this->select();
$select->from('users');
if ($sql)
{
return $select; // vráti Zend_Db_Select
}
return $this->fetchAll($select); // vráti Zend_Db_Table_Rowset
36. throw ! Exceptions
● Nevracať false/null, pokiaľ je očakávaný
objekt
● Vyhodiť výnimku
public function getUser()
{
$user = Users_Table::getInstance()->find($this->user_id);
return $user;
}
$user = $event->getUser();
if ($user == false)
{
// BLA BLA BLA - Handle error
}
else
{
$user->sendInfoMail();
}
37. throw ! Exceptions
● Nevracať false/null, pokiaľ je očakávaný
objekt
● Vyhodiť výnimku
public function getUser()
{
$user = Users_Table::getInstance()->find($this->user_id);
if (empty($user))
{
throw new Users_Exception('No user exists');
}
return $user;
}
$user = $event->getUser();
$user->sendInfoMail();
38. Neriadené strely
čo ak sa stane nemožné
● každý switch musí mať default
● vyhodenie Exception v potrebnom okamihu
● magická funkcia ktorá akceptuje čokoľvek
○ riziko preklepu
39. Pravidlo jeného ”switch” - u
● Príkaz switch / case pretaviť do najlbšej časti systému
● Používať jedine na vytváranie polymorfných objektov vo
factory
● Inak vzniká riziko opakovania toho istého switch / case
rozhodovania v inej časti systému
● Predchádza sa tým logickému zdvojeniu kódu
40. Všetko toto VYMAZAŤ !!!
Mŕtvy kód = Dead man
● Funkcie (triedy, moduly ... ), ktoré nikto
nevolá
● Vetvy podmienok, ktoré nie sú nikdy
vykonané
● Vetvy switch / case ktoré nikdy nenastanú
● Catch príkazu try, ktorý nikdy nevykoná
throw exception
● Premenné ktoré nie sú nikde použité
41. Čitateľnosť kódu
Zapúzdriť podmienky do funkcií
if ($event->start_date < $now && count($event->getBookings) > 0)
{
$event->delete();
}
if ($event->canBeDeleted())
{
$event->delete();
}
44. Závislosť na prostredí
● kód nesmie byť natvrdo závislý na prostredí /
nastevení prostredia
● namiesto toho použiť konštanty
if (APPLICATION_ENVIRONMENT == 'production')
{
$url = 'www.example.com';
}
else
{
$url = dev.example.com';
}
$url = CONSTANT_URL;
45. Zanechajte táborisko čistejšie,
ako ste ho našli!
Skautské pravidlo
● V každom projekte je potrebné robiť kontinuálny refactoring
● Pri každom zásahu do kódu urobte predchádzajúci kód trochu čistejším
● zmena názvu premennej / funkcie
● granulácia funkcie na niekoľko menších
● odstránenie krátkeho ”if” - u …
46. veľká vďaka všetkým autorom
Bibliografia
● Čistý kód - Robert C. Martin
○ (Clean Code: A Handbook of Agile Software Craftsmanship)
● Co programátory ve škole neučí - Petr Paleta
● Z kodéra vývojářem - Mike Gunderloy
○ (Coder to Developer)
● Programátor pragmatik - Andrew Hunt, David Thomas
○ (The Pragmatic Programmer)
47. priestor na diskusiu, súboje, prestrelky :)
created by Martin Rázus 2012
Ďakujem za pozornosť