Tento článek se zabývá otázkou zda a kdy
optimalizovat javovský kód. Podnětem pro jeho napsání
byla diskuze v javovské konferenci na java.cz a
podobně zaměřený, avšak obsahově odlišný, článek na
serveru interval.cz.

Nejprve trochu historie: v začátcích byla Java
často kritizována za to, že je pomalá. Rychlost Javy
se tenkrát dala těžko srovnávat např. s jazykem C a
proto si v této době spousta lidí kladlo otázku “jak
v Javě psát efektivní (rychlé) programy”. Následně se
objevila spousta triků, které měly zaručit rychlejší
provádění. Např. používání StringBuffer či StringBuilder pro sčítání řetězců
místo operátoru + (v omezené míře
platí i dnes) či procházení kolekce ArrayList pomocí metody get
místo iterátorem (platí stále). Tyto optimalizace si
bohužel někteří programátoři vyložili jako návody pro
psaní programů a autoři “neefektivních” konstrukcí
byli mnohdy pranýřováni. Jde však o nepochopení či
neznalost základních pravidel optimalizace:

Ve věci optimalizace se držíme dvou
pravidel:


Pravidlo 1. Nedělejte ji.


Pravidlo 2 (pouze pro experty). Zatím – tj. dokud
nebudete mít čisté a neoptimalizované řešení – ji
nedělejte.


[M. A. Jackson: “We follow two rules
in the matter of optimizations:


Rule 1. Don’t do it.


Rule 2 (for experts only). Don’t do it yet – that is,
not until you have a perfectly clear and unoptimized
solution.”]

Tento citát je z roku 1975 a více než tři
desetiletí mu na platnosti nic neubraly. Další často
uváděný citát týkající se optimalizace je dokonce o
rok starší:

Zhruba v 97% případů bychom měli zapomenout na
malé výkonnostní optimalizace: předčasná optimalizace
je původem všeho zla.



[D. E. Knuth: “We should forget about small
efficiencies, say about 97% of the time: premature
optimization is the root of all evil.”]

Proč je předčasná optimalizace špatná? Jen málokdy
vede k požadovanému výsledku, protože programátor
většinou nedokáže odhadnout, kde program tráví
nejvíce času. Zato podstatně snižuje srozumitelnost
kódu, protože ten je zaplevelen “efektivními”
konstrukcemi, nad kterými si čtenář často láme hlavu.
Proto by měl každý vedoucí projektu všechny
“optimalizátory” vytahat za uši. Prioritou
softwarového inženýra by měl být srozumitelný a čistý
kód (“čistý” zde znamená bez optimalizací). Vždy je
lepší nechat optimalizaci na JITu, který je napsán
tak, aby uměl optimalizovat běžný (“hloupý”) kód [B.
Goetz: “Write dumb code.”]. Neznamená to ovšem, že
máme psát jako dřevorubci. Např. zbytečné volání
metody je samozřejmě špatné a měli bychom se ho
vyvarovat. Hranice mezi předčasnou optimalizací a
kódem dřevorubce není ostrá a její vymezení může být
subjektivní. Např. zápis

 

for (int i = 0, n = p.size(); i < n; i++) {

...

}

lze považovat za předčasnou optimalizaci i za
elegantní vyjádření toho, že se počet prvků kolekce
p v cyklu nemění.

Kdy je tedy vhodné optimalizovat? Pokud máte
funkční řešení a chcete jej optimalizovat, použijte
profiler a hledejte místo, kde program tráví nejvíce
času [K. Pepperdine: “Measure, don’t guess.”]. Vždy
změřte výkon před optimalizací a po ní a optimalizaci
ponechte pouze pokud se osvědčí. Optimalizace, která
program nezrychlí, nemá v kódu co pohledávat.

Na závěr ještě pár rad pro všechny softwarové
inženýry:

  1. Zaměřte se na architekturu a
    návrh.
    Dobrá architektura je pro výkon
    programu zdaleka nejdůležitější.
  2. Používejte osvědčené
    frameworky.
    Frameworky jsou obvykle
    napsány experty v daném oboru a měly by být prosty
    výkonnostních neefektivností.
  3. Používejte efektivní algoritmy. Algoritmus s lepší časovou složitostí ovšem
    nemusí ve vašem případě dávat výsledky rychleji než
    jiný se složitostí horší.
  4. Pište srozumitelný kód. Z
    kódu by mělo být zřejmé, co jste chtěli vyjádřit.