Dobré praktiky

Dobré praktiky při vývoji software

Abychom minimalizovali vlastní chybovost při vývoji software, abychom mohli lépe vzájemně spolupracovat na společných software projektech, abychom rozuměli vlastnímu i cizímu kódu nyní i za léta, abychom byly efektivnější při práci, abychom uživatelům našeho software nabídli lepší zážitek, je dobré se při vývoji držet dobrých praktik.

1 Prostředí vývoje

1.1 Umístění projektu

Pracujeme-li ve Windows, tak projekt neumisťujeme ani na plochu ani do dalších uživatelských složek (dokumenty...). Ideálně si na nesystémovém disku D vytvoříme složku development nebo jen dev a v ní pak jednotlivé složky našich projektů. Toto můžeme pak jednoduše ještě dále strukturalizovat. Cesta k našemu projektu pak může vypadat například takto: D:\development\web_projects\library.

Takovéto složky zálohujeme na lokální cloud, napojíme na git atp...

1.2 Pojmenování souborů a adresářů (složek)

U názvů souborů a složek používáme jen znaky a-z, A-Z, 0-9, _ a -. Vyhneme se diakritice, mezerám a dalším speciálním znakům. Předejdeme tím tak problémům s různými souborovými systémy a například problémy s propojením složky na WAMP server.

Složky pojmenováváme standardně dle obsahu například app, src, www, js, css, libs...

U souborů dodržujeme standardní přípony například: html, js, php, py, c...

1.3 Adresářová struktura

Není dobré mít všechny zdrojové soubory v jedné složce. Struktura by měla být zřejmá. Některé technologie (composer, npm...) již pracují se zaběhlými strukturami, aby bylo například možné použít autoloader souborů.

Příklad struktury webové aplikace:

/project-name
— /.git
— /.vscode
— /src
  — /models
  — /views
  — /controllers
— /data
— /www
  — /img
  — /css
  — /js
  — /scss
— /vendor
— /test
— .htaccess
— conf.ini
— index.html
— README.md

1.4 Zálohujte

Jak říkával můj kamarád: "Lidé se dělí na ty, kteří nezálohují a na ty, kteří už zálohují."

Své práce zálohujte (často a pravidelně) na světové nebo své lokální cloudy (např. Synology). Ideálně použít službu GIT třeba na githubu. Nezálohujte si něco, co můžete kdykoliv stáhnout z oficiálních zdrojů (DBMS, IDE...).

2 Zdrojový kód

2.1 Pojmenovávání obecně

U názvu proměnných, konstant, tříd, metod atp obecně nepoužíváme diakritiku, mezery, čísla na začátku atp. Držíme se obvykle jen znaků a-z, A-Z, 0-9, _ a -. Něco nám nedovolí ani syntaxe jazyka. K pojmenovávání také obvykle používáme anglický jazyk, který je v IT obecně univerzálním komunikačním jazykem.

2.2 Název proměnné

Proměnné pojmenováváme stručně, ale ideálně tak, abychom již z názvu tušili, co je v ní uloženo. Pro víceslovné názvy používáme obvykle Camel Case např. selectedRows nebo minCircleRadius. Pro iterace používáme obvykle názvy i, j, k, pro obecná čísla nebo hodnoty souřadnic pak x, y, z, pro obecný počet pak n.

2.3 Název konstanty

Konstanty pojmenováváme kompletně velkými písmeny (Uppercase, Troll Case). Pro víceslovné názvy používáme obvykle Snake Case např. DB_PASSWORD nebo DEFAULT_APP_LANG

2.4 Název funkce

Funkce vykonávají nějaký sled operací. Ideálně je pojmenujme tak, aby z názvu bylo patrné, co funkce provádí např. clear_screen, případně co funkce vrací např. factorial. Pro víceslovné názvy se obvykle používá Camel Case např. getRadius případně Snake Case např. generate_table. Je vhodné si zvolit jednu notaci a tu používat v celém projektu. Preferuji Camel Case.

2.5 Název třídy nebo rozhraní

Pro názvy tříd se používá obvykle Pascal Case např. UserModel nebo HomePagePresenter. Je zvykem, že pro celou třídu je vytvořen právě jeden soubor, který se jmenuje stejně jako třída. Také je dobré nějak rozlišit interface již v názvu. Je běžné použít prefix I např. IAnimal nebo, pokud rozhraní vyjadřuje vlastnost (schopnost), pak např. Movable.

2.6 Název atributu

Název atributu tvoříme podobně, jako název proměnné. Používá se Camel Case. Měl by být samopopisný. Atribut se volá vždy z nějakého kontextu (třída, objekt), není tedy nutné, aby v jeho názvu byl název třídy atp... Bývá zvykem, abychom předešli chybnému obsahu, že se atribut nastaví na private a manipuluje se s ním pomocí metod.

2.7 Název metody

Metody manipulují s atributy a podobně jako atributy (proměnné) se tvoří i jejich název. Používá se Camel Case. Metody obvykle mění stav objektu, proto by měla být i z názvu patrná činnost např. clearMask nebo changeUser. Bývá zvykem vytvoření tzv. getterů (vrací hodnotu atributu) např. getRadius a setterů (nastavují hodnotu atributů) např. setRadius.

2.8 Počty řádků kódu

Špatně se pracuje s kódem, který má tisíce řádek, které jsou v jednom souboru nebo jen v bloku {}. Každý blok by tak měl mít do cca 30 řádek a soubor do cca 400-600 řádek. Pokud jich je více, je dobré se zamyslet nad restrukturalizací kódu. Každá funkce by měla řešit jen jednu svou problematiku.

2.9 Vnořování

Vnořování je prima, jen ho nesmí být přespříliš. Čtyři stupně jsou OK. U hlubšího zanořování je potřeba se již zamyslet nad restrukturalizací.

Mějme kód:

if(cond#1){
  if(cond#2){
    return true;
  }else{
    return false;
}else{
  return false;
}

Místo toho můžeme napsat toto:

if(!cond#1 && !cond#2){
  return false;
}
return true;

2.10 DRY

Zkratka DRY (Don't repeat yourself) míní, že není dobré, aby se ve zdrojovém kódu něco opakovalo. Opakovat se pak mohou i chyby. Opravit to nemusíme u všech výskytů. Kód je nepřehlednější a hůře se opravuje. Budeme-li chtít funkcionalitu zlepšit, musíme změnu zanést opět do všech výskytů. Pokud tedy začneme psát kód, který podobný jsme již v našem programu psali, bude vhodné použít např. cyklus nebo si na tento kód napsat vlastní funkci a tu již na patřičných místech jen volat. Programujeme tak více obecně, hromadně. Vytvořené funkce pak můžeme použít i v dalších jiných projektech (znovupoužitelnost).

2.11 KISS

"Keep It Simple, Stupid!" neboli "Zachovej to jednoduché, hlupáku!" Toto pravidlo říká, že je dobré udržovat kód jednoduchý a tím i dobře pochopitelný. Není vždy dobré optimalizovat kód na počty řádků a vymýšlet komplikované zkratky. Čemu porozumíte rychleji? Tomuto:

return x>0?fce(x):(x<0?fce(-x)/2:0);

nebo tomuto:

result = 0;
if(x>0){
  result = fce(x);
}else if(x<0){
  result = fce(-x)/2;
}
return result;

2.12 Komentáře

Nezapomínejme si některé důležité části kódu komentovat. Rychleji si tak pro příště připomeneme, jak daná funkce pracuje. Každý jazyk komentáře podporuje. Obvykle se jedná o řádkové komentáře // ... nebo blokové komentáře /* ... */.

2.13 Dokumentační komentáře

V OOP je zvykem komentovat třídy, atributy a metody. Používají se k tomu speciální dokumentační komentáře /** ... */, které mají svá speciální pravidla. Můžeme přesně uvést základní popis třídy (metody i atriburtu), parametry funkce @param, typ návratové hodnoty @return, autora třídy @author a mnoho dalšího. Tyto komentáře jsou pak používány k napovídání při psaní kódu v IDE a také se z nich dá mnohdy vygenerovat dokumentace pro API.

2.14 YAGNI

YAGNI neboli "You aren't gonna need it" značí, že není třeba psát kód na něco, co by možná mohlo být potřeba. Zbytečně tak vytváříme prostor pro další chyby. Programujme jen to, co je potřeba. Podobně platí i princip "Neopravuj, co není rozbité".

2.15 Buďte obezřetní

Pište kód tak, jako byste očekávali to nejhorší. Předpokládejte všechny varianty, které Vám mohou uživatelé zadávat na vstupu. Předpokládejte pády systémů.

2.15 Build & Fix

Zadaný problém rozdělíme na mnoho menších problémů (Divide and conquer), které lze psát postupně. Každou část tak po vytvoření otestujeme, zbavíme chyb a poté pokračujeme dál.

2.16 Testujeme

Nejprve zajistíme funkčnost kódu. Tedy, řeší-li to, co bylo v zadání. Poté optimalizujeme na výkon. Každou fázi je dobré testovat. Pro testování je dobré používat automatické Unit testy, které si píšeme průběžně se vznikajícím kódem.

3 Databáze

3.1 Pojmenovávání databáze

Pro název databáze je dobré dodržovat standardní praktiky pojmenovávání. U názvu databáze tedy použijeme angličtinu, Lowercase (malými písmeny), bez diakritiky základními znaky s použitím Snake Case např. library, elite_crm, world_cms...

3.2 Pojmenovávání tabulek

Tabulky (entitní typy) pojmenováváme anglicky, Lowercase (malými písmeny), bez diakritiky základními znaky s použitím Snake Case např. movie, genre, movie_has_genre... Jedná se o podstatná jména, kde se vede u mnohých vývojářů boj o to, má-li to být jednotné nebo množné číslo. Mé doporučení je jednotné číslo, které přináší méně problémů s podivnými tvary slov a přirozenější užití u ORM. Na druhou stranu množná čísla lépe vystihují obsah tabulky a jsou méně náchylná na konflikty s klíčovými slovy.

3.3 Pojmenovávání atributů

Pro atributy (vlastnosti záznamů, sloupce tabulek) používáme podobná pravidla, jako u databází a tabulek, tedy angličtina, Lowercase, Snake Case např. id, name, full_name... Nepoužíváme prefix s názvem tabulky. V  případě, že použijeme zápis i s názvem tabulky např. movie.name, je vše jasné a přehledné.

3.5 Primární klíče

Primární klíč jsou nejčastěji jeden číselný sloupec tabulky. Ideální je tedy jej pojmenovat id a nastavit mu UN a AI. Později to oceníte ve zdrojovém kódu programu při použití s ORM. Je zbytečné používat prefix s názvem tabulky, v SQL zase můžete použít i název tabulky movie.id, což stačí a vypadá lépe než movie.movie_id.

U M:N vztahových tabulek je pak primární klíč n-ticí cizích klíčů, které je vhodné pojmenovávat např. movie_id a genre_id v tabulce movie_has_genre

3.4 Cizí klíče

Cizí klíč slouží nejčastěji pro 1:N a M:N vztahy a je primárním v jiné (cizí) tabulce. Proto je vhodné u něj naopak cizí tabulku uvést. V tabulce movies pak bude cizí klíč country_id. Hned je pak z názvu zřejmé, že se jedná o cizí klíč, který odkazuje na záznamy v tabulce country.

3.4 SQL dotazy

Pro lepší přehlednost v SQL dotazech je dobré klíčová slova psát velkými písmeny (Uppercase) a jednotlivé části dotazu psát na nové řádky.

SELECT movie.*
FROM movie
  JOIN genre ON genre_id = genre.id
WHERE genre.id IN(1, 3, 8)
ORDER BY movie.year DESC
LIMIT 10