Bez komentáře
Tento článek byl napsán v roce 2014. Vývojářské technologie se neustále inovují a článek již nemusí popisovat aktuální stav technologie, ideální řešení a můj současný pohled na dané téma.
Komentujete poctivě Váš zdrojový kód? Když jsem se takto zeptal na poslední mé přednášce, přihlásilo se 80% posluchačů. Na otázku a proč už ale nikdo odpovědět nedokázal. Je správné kód komentovat? A jak? V tomto postu Vám sdělím můj názor na celou problematiku.
Microsoft to dělá správně
Často se střetávám s názorem, že když si někdo není něčím jistý, dívá se na kód dotnetích knihoven. V mnoha případech se jedná o inspirativní metodu nebo možnost, jak získat jiný pohled na věc. Nicméně v případě komentování mohu rovnou na jedné .NET třídě ukázat, proč je komentování kódu často zbytečné. Takhle to dopadá, když má vývojář nakázáno všechno komentovat:
Komentář v podstatě říká to samé, co název třídy. Důvod, proč jsou některé zdrojové kódy do poslední proměnné komentovány je jednoduchý: Když musíš, tak musíš.
Vycházím z Vaší zkušenosti
Než budu kázat vodu, zkusme si malý test. Vyvíjejte celý den aplikaci tak jak jste zvyklí a zkuste se soustředit na to,
- jak často si najíždíte na název třídy nebo metody ve VS, abyste zjistili, co dělá,
- když už zjišťujete co dělá nějaká třída / metoda / cokoliv, není to proto, že její název není dostatečně výstižný?
- nestává se vám spíše, že se díváte dovnitř těchto stuktur? (tedy potřebujete vědět, jak to dělá, spíše než co dělá)?
Moje zkušenost je taková, že z dobře napsaných názvů tříd, metod a členů nemám potřebu zjišťovat co daná metoda dělá. Pokud už najíždím na název nějaké struktury, tajně doufám, že se dozvím něco dalšího (že mi bude odhalena odpověď na otázku JAK)
Hlavně to dobře pojmenuj
V první řadě je důležité používat maximálně výstižné popisné názvy tříd, metod i proměnných. Čím lépe jsou všechny členy pojmenovány, tím méně vzniká potřeba kód komentovat. Já se za sebe řídím dvěma pravidly:
- Když nemám potřebu kód komentovat, nekomentuji
- Když dostanu "chuť" něco okomentovat ale nevím co napsat, nekomentuji a raději ještě zkontroluji všechny názvy členů v kódu
Nemám problém s dlouhým názvem proměnných a konvence jazyka jsou pro mě důležitější než konvence reálného světa. SIPO
zkrátka v kódu má být Sipo
. V dodržování konvencí mi pomáhá ReSharper, který se dá velmi dobře nastavit.
Komentář je cukr
A mnoho cukru obvykle neprospívá. Když už si ale chcete osladit kód, udělejte to tak, aby z toho každý, kdo bude s kódem pracovat měl nějaký prospěch. Kdy se tedy komentáře hodí?
Působnost třídy
Občas je ideální popsat celkovou působnost třídy. Chcete-li pracovat s repositářem, například ArticleRepository
, už tak nějak očekáváte, co bude umět. Co když ale budete hledat třídu související s kompilací MarkDown a v nabídce budete mít Markdown
a MarkdownService
? Když se začnou množit nestandardní třídy, které budoucí vývojáři nemusí znát, je dobré popsat působnost:
// Kontejner umožňující vznik Markdown objektů a jejich serializaci public class Markdown(){} // Služba poskytující metody pro práci s Markdown objekty a kompilaci public class MarkdownService(){}
Jak to ta metoda dělá
Někdy je dobré sdělit základní myšlenku metody nebo popsat v jedné větě její algoritmus.
public static class ImageExtensions { // Projde všechny 4 strany obrázku a u každé samostatně odstraní jednolitou barvu (považuje za okraj fotky) public static Bitmap RemoveBorderFromImage(this Bitmap bmp) {......} }
K čemu ta proměnná je
Pochopit co proměnná znamená a co následně ovlivňuje jsou dvě věci.
public class ExceptionHandler { // Email technické podpory zobrazený v uživatelských výstupech public string SupportEmail {get; set;} }
I když v příkladu výše bylo zřejmé, že SupportEmail
patří technické podpoře, nebylo jasné, zda na tento email budou zasílány chyby nebo se jedná jen o email zobrazený v nějakých výstupech.
Organizace práce
Užitečné mohou být komentáře pro vytváření tasklistů přímo ve VS. Přestože pracuji se standardním backlogem, některé tasky jsou tak malé, že se je hodí napsat přímo do VS. Když pak implementujete větší modul, hodí se postavi si infrastrukturu, zaměřit se na kritické místa a teprve nakonec dodělat křoví, které už obvykle neskýtá problém. Právě aby se na křoví ke konci nezapomělo, hodí se používat tyto tasky:
public class ArticleRepository(..) { public PagedList<Article> GetArticlesOfMonth(int year, int month) { // TODO: Zamyslet se nad typy (month - int?) // TODO: Implementace metody repositáře throw new NotImplementedException(); } }
S TODO umí pěkně pracovat i ReSharper, který umí definovat i vlastní klíčová slova, která zobrazuje v přehledném oknu. Co navíc, dokáže identifikovat NotImplementedException a automaticky ji přidat do Todo Listu.
Generování dokumentace
Vygenerované dokumentace jsem nikdy neměl moc rád. Pro laika jsou v podstatě těžko uchopitelné a pro vývojáře je mnohdy lepší si kód projít. Existuje výjimka. Web Api. Dnes jsou aplikační rozhraní velmi oblíbená a například pro ASP.NET Web Api existuje geniální plugin Help Page, který dokáže přečíst XML s dokumentací a vygenerovat srozumitelnou a použitelnou dokumentaci za pomocé nové MVC Area. Protože je kód otevřený, je možné si kompletně změnit styl i veškerý způsob generování.
Aby vše fungovalo, je pak samozřejmě nutné důsledně mít celé API popsané pomocí komentářů. Metody, třídy i všechny proměnné. A to je práce, která za to celkem stojí.
Jak komentáře nepoužívat
Téměř nakonec bych uvedl ještě typické příklady komentářů, které se v aplikacích hojně vyskytují a jsou přitom zbytečné. Nejen, že komentáře jsou zlo, které vede k větší nepřehlednosti ale zároveň dávájí prostor pro vznik chyb.
Zakomentováno ale nepoužito
Běžná praxe je zakomentovat kód, který zrovna není potřebný. Uteče měsíc a ani vy, ani nikdo jiný nejste schopen říct k čemu onen zakomentovaný kus kódu nebo řádku je. Bojíte se ho smazat a tak tam hnije do nekonečna. Dám Vám několik tipů, které pro NEpsaní komentářů dobře fungují.
Řiďte chování prostředí kódem (ne manuálně)
Co třeba takový zakomentovaný řádek? Obvykle je důkazem lenosti nebo špatného návrhu v systému. Než aby vývojář provedl nastavení projektu, raději "swapuje" manuálně mezi dvěma řádky. Příkladem budiž:
url = "http://localhost:54564"; // url = "http://www.mujweb.cz";
což se dá bez komentářů přepsat:
string url; if(Request.IsLocal) url = "http://localhost:54564"; else url = "http://www.mujweb.cz";
Vyhnout se manuálnímu swapování znamená i zamezit riziku vzniku chyby.
Nehrajte si na bohy a neměňte prostředí
Máte proměnnou o určité hodnotě ale potřebujete odzkoušet, jak se aplikace zachová, když její hodnota bude jiná. Nejhorší, co můžete udělat je tuto změnu chování řídit kódem, který po otestování jak jinak než zakomentujete. Opět příklad:
public ActionResult Index(string name) { // name = "muj-clanek"; var article = articleRepository.GetByName(name); }
I taková situace se dá snadno řešit přepnutím do debug módu a manuálním přepsáním hodnoty name
. Pro důkladnějsší otestování se pak hodí Unit Test. Přepisovat hodnotu přímo v kódu je ale risk.
Používejte source control
Smazat kód občas může mrzet. Ne když ale používáte Source Control. Proč nechávat v aplikaci kód, který není použitý?
//public string GetAdvice(string name) //{ // return "Hey " + name + ", let's go to the pub!"; //} public string GetAdvice(string name) { return string.Format("Hey {0}, let's go to the pub!", name); }
Prvním krokem je, naučit se Source Control používat. Dokázat najít předchozí verze, porovnat je se současnou a najít rozdíly. Když víte, že checkin neznamená žádnou ztrátu ale pouze novou verzi, máte vyhráno.
Metodu označte jako Obsolete s komentářem
Open/Closed Principle je jeden z nejporušovanějších principů SOLID. Nutno dodat, že speciálně zásah do metod a jejich změna chování je důvodem, proč vznikají komentáře podobné v předchozí ukázce. Výjimkou jsou z mého úhlu pohledu drobné změny v kódu související s refactoringem a předpoklad existence Unit Testu + dodržení SRP.
I tak je ideální ponechat metodu dočasně živou a vydat jejího nového následovníka.
[Obsolete("Tato metoda již nebyla výkonnostně optimální. Použijte raději GetTheAdvice.")] public string GetAdvice(string name) { return "Hey " + name + ", let's go to the pub!"; } public string GetTheAdvice(string name) { return string.Format("Hey {0}, let's go to the pub!", name); }
Continuous Code Improvement
Už několik let stojím za myšlenkou, že kód by se měl opuštět vždy v lepším stavu, než když jej navštívíte. Je to skvělé pravidlo. Brouzdáte kódem, vidíte někde něco co se dá vylepšit, tak to opravíte. Opět v tomto ohledu silně pomáhá ReSharper, který se stárá o to, aby se tím nic moc nerozbilo. Když jsem vybral vhodný název pro tento odstavec, a sice Continuous Code Improvement, narazil jsem na tento skvělý článek Roberta Greinera. Nicméně s myšlenkou CCI se setkáte i v knize Roberta C. Martina, Clean Code, která by měla patřit do povinné četby každého vývojáře.