Dnes mám nějakou náladu na filozofování, tak napíši něco, čeho už jsem se několikrát dotkl. Takže žádná novinka. Začnu svým oblíbeným prohlášením. Já píšu programy pro uživatele, snažím se řešit nějaký jejich problém. Říkejme tomu business problém. Rozhodně nepíši operační systémy, programovací jazyky, vývojová prostředí ani knihovny. Obvykle píši něco, co mému zákazníkovi přináší nějaké peníze.
Počítače ale pořád ještě pracují s nulami a jedničkami, od kterých je k penězům setsakra daleko. A od toho tu právě jsou abstrakce. Operační systém mě odstíní od těch nul a jedniček, virtuální stroj mě odstíní od operačního systému a správně zvolené knihovny mě odstíní od virtuálního stroje.
V ideálním případě bych měl psát kód, který co nejblíže popisuje řešení daného business problému. Pokud to tak není, je něco špatně. Pokud musím v kódu kopírovat pole bytů, starat se o vlákna, řešit systémové výjimky, starat se o paralelizaci, tak vím, že je někde chyba. Já chci prostě a jednoduše psát jenom business kód.
A nejsem to jenom já, podívejme se tímto pohledem na úspěšné technologie. Můžeme začít třeba samotnou Javou. Ta uspěla také díky tomu, že programátora odstínila od spousty do té doby běžných infrastrukturních starost. V Javě už jste se nemuseli starat o dealokování paměti, nemuseli jste řešit, jestli je String ukončený nulou nebo čím, nemuseli jste řešit jaký typ procesoru používáte nebo jaký je rozdíl mezi endianem a indiánem. V Javě jste se mohli jste se soustředit na psaní kódu. (Ano vím, že Smalltalk to uměl už o sto let dříve).
Podobně úspěšné je servlet API. To nám zas umožňuje chovat se k vícevláknovému systému tak, jako by v něm bylo jen jedno vlákno. Ano, jako každá abstrakce i tato prosakuje, ale v zásadě to tak je. Vsadil bych se, že tato podařená abstrakce stojí za úspěchem servlet API a tím pádem i enterprise Javy. Naopak špatnou abstrakci poznáte podle toho, že vás nutí dělat něco, co byste jinak nedělali. Třeba EJB 2 a jeho šílená rozhraní.
Nejen že mi dobrá abstrakce umožňuje se soustředit na můj business problém, ona mi i umožňuje držet krok s vývojem. Změní se operační systém? Nic se neděje. Změní se architektura procesoru? Nezájem, já jsem svůj program napsal v obecnější rovině, takže mě to (pravděpodobně) neovlivní. Naopak, já mohu využít novinek aniž bych na svůj kód třeba jen šáhnul. Procesor má tisíc jader? Nevadí, jenom změním konfiguraci serveru a mám vystaráno. Práce s více vlákny je pomalá? Nevadí, udělám update JVM a hned je vše jinak. Moje problémy za mě řeší někdo jiný.
A to je vlastně důvod, proč to všechno píši. Pokud mě někdo nutí zahrnout do programu něco, co nevyjadřuje business problém, vím že je to špatně. Pokud mě někdo například nutí používat asynchronní API a z mých požadavků to přímo nevyplývá, vím, že se snaží řešit problém na nesprávném místě. Často není vyhnutí, často není technologie dost pokročilá. Ale většinou je to prostě jen špatná volba.
Představme si, že například nechci, aby uživatel čekal, až se mi data zapíší do databáze, tak jak to píše Dagi. Samozřejmě, že to mohu řešit v kódu. Ale tam já to řešit nechci, tam já chci řešit jenom business. Musím se proto zamyslet jak to dělat jinak. Použít rychlejší databázi? Použít lepší JDBC ovladač? Použít databázi, která bere transakce velmi benevolentně? Všechno je možné, změna kódu je až poslední varianta.
Je tu ještě jeden z argumentů, který jsem zatím nezmínil. Lidé, kteří píší knihovny, databáze nebo virtuální stroje tomu rozumí mnohem lépe než já. Já vím jak převádět peníze, oni rozumí transakcím. Já vím co zajímá zákazníka, oni vědí jak synchronizovat data mezi vlákny. Kdykoliv to musím řešit za ně, vím, že buď odvedli špatnou práci nebo že já jsem si zvolil špatnou technologii.
Vemte si například ParallelArray. To mi umožňuje provádět operaci nad poli paralelně. Úžasná a i převratná knihovna. Ale z mého pohledu je špatná v tom, že mě nutí řešit thread pooly. To já nechci, to zákazníka vůbec nezajímá. Zamysleme se, proč to za mě nemůže řešit někdo jiný. Řekněme, že zavolám klasické Arrays.sort(). Proč nemůže běžet paralelně? Že JVM neví kolik vláken se má použít? Jak to že ne? To to ví dokonce lépe než já. Virtuální stroj dokonce i ví, kolik přesně má v daném okamžiku volných procesorů. To já nikdy v okamžiku psaní programu nevím a vědět nikdy nebudu. Že neví jestli je to operace k paralelizaci vhodná? Jak to? HotSpot to ví zase mnohem přesněji než já. To je stejné, jako kdybyste tvrdili, že je lepší, když programátor ručně uvolňuje paměť nebo optimalizuje kód.
Tak se nad tím prosím zkuste zamyslet. Třeba nad tím jak do toho všeho zapadají dynamické jazyky, DSL a podobně. Připadá mi, že to všechno dává docela smysl.
Když jsem začínal s Javou (1.1), vždycky jsem si říkal: “To je paráda, můj program bude každý rok rychlejší. To když Sun vydá novou Javu s ještě lepšíma optimalizacema.” Ovšem praxe ukazuje, že to zatím není žádná sláva.
Kompatibilita je nadevše. Kolikrát už jsme přece slyšeli, že něco nemůže být opraveno, protože prostě “příliš mnoho programátorů už mají stávající kód závislý na této (špatné/pomalé) implementaci”.
Takže mě napadá – možná by byla situace lepší, kdyby J2 Core API byla kvalitnější.
Přidám ještě jednu myšlenku. Postupně, jak jsem pronikal do tajů Javy, jsem si opakovaně kladl otázku: “Nešlo by to všechno (API) zahodit, udělat tlustou čáru a začít s čistým štítem?” Zřejmě to je jen sen…
kvalitnější = taky abstraktnější (tam jsem mířil)
“Pokud tomu tak není, je něco špatně”
Jo, ale někdy je špatné řešení tím nejlepším možným. Nechci, aby se tento můj post stal omluvenkou pro prasárny všeho druhu, ale někdy je prostě systémové řešení tak drahé a náročné, že, řečeno z ekonomického hlediska, si na sebe nevydělá.
@v6ak: Máš pravdu, často je to ale naopak. Často je to abstraktní řešení to nejjednodušší. Například chci setřídit pole, použiji Arrays.sort(), chci zapsat do databáze, použiji Hibernate. Neřeším výkonnost, doufám, že ji za mě vyřeší někdo, kdo tomu rozumí víc. To ošklivé, drahé a náročné řešení nastoupí až když přijdu na to, že technologie ještě není tak daleko, aby uspokojila moje požadavky.
Jasně, myslím, že se na to díváme stejně. (Viz “Nechci, aby se tento můj post stal omluvenkou pro prasárny všeho druhu, ale někdy je prostě systémové řešení tak drahé a náročné…”)
Nejvetsi proble s abstrakcema vseho druhu neni technicky, ale socialni. Urcita sorta vyvojaru proste neveri cemukoliv co si sami nenapsali. Nejcastejsi argument proti abstrakcim je “vzdyt tomu nebude nikdo rozumet, az se tam neco rozbije”, pripadne “nikdo poradne nevi co se tam deje a pak jsme prekvapeny, jak zvlastne se to chova”. Podle me je to takove zpatecnicke mysleni, ja ty argumenty sice uznavam, ale cemu dnes k sakru pri te slozitosti rozumime?!
Arrays.sort() muze bezet paralelne a verim, ze brzy pobezi. Nekdy je vsak vhodnejsi rucni paralelizace, protoze najit optimalni pocet vlaken pro dany problem nemusi byt jednoduche. A pak nastupuje ForkJoin.
Podle mně nemusí být abstrakce, ale stačí, aby daná knihovna/jazyk měl jednoduché a bezpečné použití pro běžné problémy a dobrý tutoriál a manuál. Tj. je mi celkem jedno, jak složité je použité ParallelArray, když někde v manuálu bude copy&paste kus kódu, který mi bude vždy (!) bezchybně fungovat, i když ne optimálně.
Např. na webu lze najít tuny blogů a kódu, které třeba špatně zavírají soubory. Přitom by stačilo v Javadocu a v manuálech zdůraznit, že soubory se VŽDY mají zavírat ve větvi finally{}.
Copy&paste? Fuj!
K zavírání: radši @lombok.Cleanup – je to mnohem jednodušší a přehlednější. Ale principiálně souhlasím.
Úplně nejlepší by bylo, kdyby programátor nemusel na zavírání souboru myslet. Stejně jako nemusí myslet na uvolnování paměti.
Již dřív jsem o tom přemýšlel. Ale ono zavření není jen uvolněním určitých systémových prostředků, ale může být spojeno třeba i s uzavřením síťového socketu nebo uvolněním zámku. A diví se vlastně někdo, že musíme odemykat zámky?