Čistý kód
alebo
ako nevariť objektové špagety
Čo je to čistý kód?
Ideal learning curve
tim
knowledg
e
Real learning curve
Čo je to čistý kód?
Čo je to čistý kód?
Č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
Viem písať čistý kód ?
JASNE :)
Varené žaby
Rozbité okná
Ako sa dostať dole?
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
Deadlines
● časový stress != bordel v kóde
● provizórium sa stáva permanentné riešenie
Č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
Ako to dosiahnuť?
"Vidím ďalej ako ostatní,
lebo stojím na ramenách obrov."
Sir Isaac Newton
Problémy
● nevedomosť
● zvyk je železná košeľa
● vlastné ego, ješitnosť
Riešenie
● súbor mnohých pravidiel
● dôraz na detail
● umenie ktoré sa dá naučiť
Coding standards
....
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
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;
}
nepoužívať skratky
$adm_usr
$admin_user
$pr_pg
$print_page
$glum
$user
Princíp najmenšieho
prekvapenia
DRY
(Don't repeat yourself)
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ť
/** Komentáre **/
Okomentovaný kód
Okomentovaný kód == dobrý kód
(Okomentovaný kód == dobrý kód) == false
/** Komentáre **/
Komentár duplikuje názov premennej
/**
* list of items
*/
private $item_list
/** 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())
/** 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();
Funkcie
● funkcia má vykonávať len jednu vec
● mala by byť malá
● granulovať logické celky
● v jednej funkcii iba jedna podmienka
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();
}
}
}
Funkcie - granulácia
public function newEventAction()
{
$this->prepareForm();
if ($this->_request->isPost())
{
$this->submitForm();
}
}
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();
}
}
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
}
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
}
}
Funkcie - argumenty
● Volanie funkcie ”po starom”
$user->sendMessage($message_text, $subject, $to_user_id, $item_id, $item_type_id, $template_id);
$user->sendMessage($message_text, $subject, $to_user_id, null, null, $template_id);
$user->sendMessage($message_text, null, null, $item_id, null, $template_id);
● Volanie funckie ”po novom”
$message = new Message();
$message
->setMessage($message_text)
->setSubject($subject)
->setReceiversIds($users_ids)
->send();
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();
}
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
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();
}
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();
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
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
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é
Č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();
}
Čitateľnosť kódu
Vyhýbať sa negatívnym podmienkam
if(!$result->isValid())
{
$this->showError();
}
else
{
$this->saveData();
}
if($result->isValid())
{
$this->saveData();
}
else
{
$this->showError();
}
Čitateľnosť kódu
Nepoužívať skrátený if
$result = ($value == 10) ? $value++ : 0;
if ($value == 10)
{
$result = $value++;
}
else
{
$result = 0;
}
return (isset($_POST['name'])) ? "Form" : ((!$sqlData) ? $data[$sqlVar] : '');
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;
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 …
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)
priestor na diskusiu, súboje, prestrelky :)
created by Martin Rázus 2012
Ďakujem za pozornosť

Clean Code / ako nevariť objektové špagety - Martin Razus

  • 1.
  • 2.
    Čo je točistý kód?
  • 3.
  • 4.
  • 5.
    Čo je točistý kód?
  • 6.
    Čo je točistý kód?
  • 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
  • 8.
  • 9.
  • 10.
  • 11.
    I don't knowhow 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
  • 12.
    Deadlines ● časový stress!= bordel v kóde ● provizórium sa stáva permanentné riešenie
  • 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
  • 14.
    Ako to dosiahnuť? "Vidímďalej ako ostatní, lebo stojím na ramenách obrov." Sir Isaac Newton
  • 15.
    Problémy ● nevedomosť ● zvykje železná košeľa ● vlastné ego, ješitnosť
  • 16.
    Riešenie ● súbor mnohýchpravidiel ● dôraz na detail ● umenie ktoré sa dá naučiť
  • 17.
  • 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; }
  • 20.
  • 21.
  • 22.
    DRO (Don't repeatothers) ● pýtať sa ● komunikovať s kolegami ● checknúť zdrojáky! ● nebyť lenivý ● nepísať novú funkciu / classu ak sa dá stará prispôsobiť
  • 23.
    /** Komentáre **/ Okomentovanýkód Okomentovaný kód == dobrý kód (Okomentovaný kód == dobrý kód) == false
  • 24.
    /** Komentáre **/ Komentárduplikuje názov premennej /** * list of items */ private $item_list
  • 25.
    /** Komentáre **/ Komentárduplikuje 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 publicfunction 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 publicfunction newEventAction() { $this->prepareForm(); if ($this->_request->isPost()) { $this->submitForm(); } }
  • 30.
    Funkcie - granulácia privatefunction 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 classMessage { 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 } }
  • 33.
    Funkcie - argumenty ●Volanie funkcie ”po starom” $user->sendMessage($message_text, $subject, $to_user_id, $item_id, $item_type_id, $template_id); $user->sendMessage($message_text, $subject, $to_user_id, null, null, $template_id); $user->sendMessage($message_text, null, null, $item_id, null, $template_id); ● Volanie funckie ”po novom” $message = new Message(); $message ->setMessage($message_text) ->setSubject($subject) ->setReceiversIds($users_ids) ->send();
  • 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 aksa 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ť podmienkydo funkcií if ($event->start_date < $now && count($event->getBookings) > 0) { $event->delete(); } if ($event->canBeDeleted()) { $event->delete(); }
  • 42.
    Čitateľnosť kódu Vyhýbať sanegatívnym podmienkam if(!$result->isValid()) { $this->showError(); } else { $this->saveData(); } if($result->isValid()) { $this->saveData(); } else { $this->showError(); }
  • 43.
    Čitateľnosť kódu Nepoužívať skrátenýif $result = ($value == 10) ? $value++ : 0; if ($value == 10) { $result = $value++; } else { $result = 0; } return (isset($_POST['name'])) ? "Form" : ((!$sqlData) ? $data[$sqlVar] : '');
  • 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, akoste 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ýmautorom 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ť