Miroslav Holec
Premium

Bez komentáře

Miroslav Holec   4. října 2014  update 29. března 2016

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:

Ukázka zbytečného komentáře

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,

  1. jak často si najíždíte na název třídy nebo metody ve VS, abyste zjistili, co dělá,
  2. 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ý?
  3. 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:

  1. Když nemám potřebu kód komentovat, nekomentuji
  2. 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.

TODO List v ReSharperu

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.