Přejít k navigační liště

Zdroják » JavaScript » Po letech opomíjení se funkcionální programování stává mainstreamem. Proč zrovna teď?

Po letech opomíjení se funkcionální programování stává mainstreamem. Proč zrovna teď?

Články JavaScript

Funkcionální programování lze jen stěží označit za novinku. Už počátkem 90. let jsem na univerzitě napsal spoustu kódu v LISPu. Před 25 lety. A už v té době byl zmíněný jazyk o něco starší než moje tehdejší študácké já.

Nálepky:

V anglickém originále zveřejněno na blog.salsitasoft.com.

Výhody funkcionálního programování jsou již dlouho známé. Úspěšný vývoj softwaru je z velké části o udržení složitosti pod kontrolou, zatímco se aplikace musí vyrovnat s náporem podmínek reálného světa. Je o boji s nerealistickými deadliny, zatímco my vývojáři kupíme jednu funkci na druhou. Toto vše je mnohem jednodušší, když se vaše aplikace skládá z dobře testovatelných čistých funkcí bez prapodivných vedlejších efektů a proměnlivého globálního stavu.

A přesto žádný funkcionální jazyk zatím nedosáhl masového užívání. Tím myslím ten typ intergalaktické nadvlády, kterou si užívalo C v sedmdesátých letech, než předalo žezlo C++, Javě a v následujících dekádách pak JavaScriptu. Ani žádný z hlavních uchazečů z nižší váhy (Python, PHP, Perl, Ruby, C#) není úplně funkcionální.

Teď se ale v tomto směru děje něco magického. Samozřejmě tu mluvím o Clojure.

Dělám si srandu! Žádný nový funkcionální jazyk světem programování v základech neotřásá, spíš se pomalu dostává do popředí funkcionální potenciál úřadujícího šampióna. Aktuálně vypomáhám s jednou mobilní aplikaci. Je založená na React/Redux a přistihl jsem se, jak píšu kód ve stylu:

aliasesList.reduce((allMatching, matching, index) => {  
  if (matching.count() > 0) {
    const expanded = allAliases.take(index)
      .concat(List.of(matching))
      .concat(allAliases.skip(index + 1))
      .filter(aliases => aliases.count())
      .reduce((current, aliases) =>
        current ? current.flatMap(
          i1 => aliases.map(i2 => i1.concat(i2))
        ) :
        aliases.map(alias => List.of(alias)),
      null);
    return allMatching.concat(expanded);
  } else {
    return allMatching;
  }
}, new List());

Hej, máš svůj LISP v mém JavaScriptu!

Proč tedy bylo FP programátorským lidem tak dlouho opomíjeno? A čím to, že je nakonec masově přijímáno?

Pryč s podstatnými jmény

Odpověď na první otázku souvisí s celkovým trendem ve vývoji softwaru. Po absolvování univerzity jsem byl smeten objektově orientovanou tsunami a dalších 20 let jsem nenapsal ani řádek LISPu. Komunita vývojářů softwaru se tenkrát rozhodla, že OOP je Jediná Správná Cesta. A tato móda ještě zesílila, když se o pár let později objevila Java. Komunita tehdy zkrátka neměla dostatek kolektivní pozornosti, kterou by mohla nebo byla ochotna věnovat funkcionálnímu programování.

Za vlády triumvirátu Zapouzdření, Dědičnosti a Polymorfismu OOP slibovalo lék na bujení softwarové složitosti. Nicméně v posledních letech se slabiny OOP stávají čím dál patrnější. Rigidní objektové hierarchie s křehkými základními třídami přispívají k bolestivé evoluci schémat. Roztahání stavových proměnných všude možně napříč kódem vede k problémům v souběžnosti a k nepředvídatelným vedlejším efektům. S tím, jak se ztrácí zalíbení v objektových „podstatných jménech“, odpovídajícím způsobem roste uznání funkcionálním „slovesům“.

V dobráckém žertu jsem si rýpnul do Clojure, ale na tomto místě by mu měla být na funkcionální renesanci probíhající v posledních letech po právu připsána zásluha. Tím, že řeší mnoho praktických problémů, které zamořily dřívější LISPy, Clojure představilo FP úplně nové generaci vývojářů. Clojure také v neposlední řadě pobídlo k vytvoření Om, což mělo obrovský vliv na evoluci dnešního JS ekosystému (viz dále).

Javascript dospěl

Krom deziluze ohledně OOP jsou spolu ony dvě výše položené otázky svázány i prostřednictvím dalších dvou trendů: Jednak v nástupu JavaScriptu jakožto plnohodnotného všestranně použitelného programovacího jazyka, jednak v tom, že si FP našlo své místo v širším JavaScriptovém ekosystému.

Na přelomu desetiletí se většina webového vývoje soustředila na server a skripty na straně klienta hrály jen vedlejší roli. Přesto několik Ajaxových průkopníků (například Gmail) už v té době demonstrovalo přitažlivost single-page aplikací běžících kompletně v prohlížeči, které chápou server hlavně jako centralizovanou úschovnu dat. Webové aplikace s rychlou odezvou tvářící se jako desktopové byly už tehdy očividně lepší než ty staré rachotiny poháněné pomocí CGI z dob webového pravěku.

Dalším posílením tohoto trendu bylo v roce 2008 vydání prohlížeče Google Chrome, který mimo jiné přinesl oproti konkurenci skokový nárůst výkonu při interpretaci JavaScriptu díky enginu V8. Bleskurychlý JavaScript byl podmínkou pro vznik „all-in-one“ frameworků pro „jednostránkové appky“, opět v čele s Googlem a jeho AngularJS. V8 se následně také stalo srdcem pro Node.js, což je samostatné běhové prostředí pro JavaScript, užívané především pro vývoj serverové části.

Najednou už JS není jen pro skriptující děcka. Angular a jeho bratři spolu s Nodem v posledních několika letech zažehli doslova explozi používání JavaScriptu.

Funkce a forma

Jak to vše souvisí s funkcionálním programováním? Brendan Eich (tvůrce JS) byl, jak sám tvrdí, najat do Netscapu v roce 1995, aby do stejnojmenného prohlížeče implementoval podporu funkcionálního jazyka Scheme. Přestože nakonec podlehl tlaku managementu, aby výsledný jazyk „vypadal jako Java“, dokázal v jazyce zachovat některé zásadní funkcionální aspekty (např. first-class funkce). Díky tomu někdy JavaScript bývá v nadsázce popisován jako „LISP s C syntaxí“.

Nakonec tak vznikl jazyk, který je velmi univerzální. Dnešní web nabízí miliony řádků kódu jako důkaz toho, že v JS můžete psát jak imperativní kód, tak kód objektově-orientovaný, nebo klidně i příšerně nechutný špagetový. Ale na rozdíl od ostatních jazyků s C syntaxí má základní vybavení, aby posloužil i jako základ pro opravdový funkcionální jazyk.

Funkcionální stálice map a reduce byly do JS (přesněji do ECMAScriptu) přidány v roce 2011. Jeho nástupce ECMAScript 2015 (původně ECMAScript 6) pak přidal několik dalších funkcionálně laděných konstruktů jako const a milovanou „fat arrow“ => s konzistentní syntaxí a konečně rozumným vázáním this. Většina funkcí ES2015 si ale na svou širší podporu v prohlížečích bohužel bude muset ještě počkat. S řešením tohoto problému nedávno přišel Babel transpiler, který umožňuje použití konstruktů z ES2015 (a dokonce i ES2016) již dnes, protože je kompiluje do pro prohlížeče univerzálně srozumitelného ES5.

Stejná reak(t)ce

AngularJS byl důležitým činitelem v boomu JavaScriptu, ale s kořeny v JavěOOP je cokoli, jen ne funkcionální. V posledních několika letech se pozoruhodnou rychlostí rozběhl React ze stáje Facebooku a stal se jedním z nejoblíbenějších JavaScriptových client-side frameworků. React je doplňován Flux architekturou a knihovnou Immutable.js, obojí též z dílny Facebooku. (Je pozoruhodné, jak se vzestup funkcionálního JS děje ve stejnou dobu, kdy můžeme pozorovat Facebook, jak odsouvá Google stranou ve snaze stát se alfa samcem JS frameworků.)

React se zdá být velmi funkcionálním přístupem k namapování stavu aplikace na webový pohled (view). Opravdu, poslední verze dokonce představila zjednodušenou syntaxi pro psaní čistých komponent bez vedlejších efektů.

React však řeší pouze problém zobrazování dat, což je také důvod, proč Facebook doporučuje pro širší architekturu aplikace využít také Flux. Díky tomu, že Flux je jen sada základních principů (stores, akce, centralizovaný dispatcher, jednosměrný proud dat), o nadvládu soupeří mnoho konkurenčních konkrétních implementací. Žádná z nich se dlouhou dobu nezdála být jasným vítězem, dokud se nedávno neobjevil Redux.

Redux je založen na třech přikázáních: jediný data store používati budeš, změna stavu pouze jako reakce na vyslanou akci se provede a změny stavu jen čistými funkcemi (tzv. reducery) prováděny jsou.

Když ještě přidáme Immutable.js, Redux začne setsakramentsky připomínat clojurovský Om. Teoreticky bylo možné JavaScriptový kód funkcionálně psát vždy, ale React, ReduxImmutable.js konečně nabízejí JS vývojářům praktické ingredience pro vytváření rozsáhlých funkcionálních aplikací: vývoj čistých reducerů bez vedlejších efektů k manipulaci s neměnitelným stavem, a to ve vypulírované ES6 syntaxi. Popularita tohoto přístupu (a tím pádem i funkcionálního programování) strmě vzrůstá: Když jsem si poprvé před několika měsíci všiml Reduxu, měl na GitHubu něco kolem 500 hvězdiček. Dnes jich tam má přes 16 tisíc!

Funkcionální budoucnost

Je trochu předčasné říci, zda nově vzniklá náklonnost k funkcionálnímu JavaScriptu přetrvá. JS krajina byla v posledních letech tak nestabilní, že se ze střelhbité kadence vzniku stále nových „Frameworků, Co Zabijí Všechny Ostatní Frameworky“ stal tak trochu vtip. Ale dlouhý rodokmen funkcionálního programování a atraktivita jeho hlubších principů naznačuje, že je nepravděpodobné jeho vyhynutí. I když budou zmíněné konkrétní implementace nahrazeny, zdá se, že roste pravděpodobnost toho, že budoucnost moderního vývoje softwaru – konečně! – bude funkcionální.

Salsita Software

Salsita Software je softwarová společnost, která se specializuje na vývoj komplexních moderních webových a mobilních aplikací. Sponzorujeme JavaScripting.com, komunitní portál, který pomáhá vývojářům hledat knihovny a frameworky pro JavaScript.

Překlad: Tomáš Křen, Luboš Turek a Adam Eda Zemek

Komentáře

Subscribe
Upozornit na
guest
20 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Pavel Francírek

Problém je, že prasit se dá v čemkoliv a mizerné programátory žádný svatý grál nezachrání. Pamatuju, jak se, s podobně oslavnými články, před skoro 30 lety vítalo OOP.

Hmmm

Iste, ale nie je to problem Javascriptu. Dokonca by som to ani problemom nenazyval, pretoze to nie je problem, ktory by mal riesenie a ktorym by sa trebalo zaoberat.
Mizerni vykonavatelia remesla budu vzdy a v kazdom remesle.

Daniel Steigerwald

Ano i ne. Ve funkcionálním programování jakoby prasíte, ale výsledkem je čistej kód. Klidně si šáhnu na global state, a nic se neděje. Proč? Je immutable, můžu z něj jen číst :-) V OOP velmi rychle něco poserete, ve funkcionálním programování kód zdaleka tak rychle nehnije.

Míra

Podle mých zkušeností opravdu nezáleží na frameworku ani programovacím jazyce.
Zatím jsem nepotkal jazyk ve kterém by se nedalo psát slušně nebo v něm naopak nešlo totálně prasit.
Knihoven a technik, které měli „zázračně“ zajistit krásný kód už jsem taky viděl spoustu. Žádná z nich nefunguje.
Kvalitní kód zajistí pouze programátor, žádná zázračná knihovna ani framework. Bez ohledu na to jakou nálepku ta knihovna má.

Bohužel v poslední době dost často vidím přístup kdy cokoliv s nálepkou Google, Facebook apod. je automaticky považována za vzor dokonalosti a toho co „všichni“ používají.

Zákazníka v drtivé většině nezajímá kolik cool a trendy knihoven se podařilo do projektu nacpat. Zákazník se zajímá hlavně o bussiness část, tj. funkčnost produktu.

Martin Hassman

Není to problém per se, je jím jen, pokud se to za problém rozhodnete považovat.

Jinak řečeno není to chyba, jen vlastnost 8-)

Dor

Nemyslím si, že by článek chtěl řešit zachraňování mizerných programátorů zlatým grálem. Zato si myslím, že oslavné články o OOP byly tehdy namístě. Nikdo neříká, že OOP je jediná možná všespása, ale určitě nevnímám OOP jako historický omyl. Ale asi ani o tom nebyl článek. Já jsem z toho hlavně vyčetl důvody, proč a jak je dneska výhodné šáhnout i po funkcionálním programování a vcelku se s tím ztotžňuju.

Oldis

Za mě za článek palec nahoru

Ivan Nový

FP je nesmysl, povede ke špageti kódu, udržovatelnost a modifikovatelnost aplikací se bude blížit 0. FP vede na vytváření mnoha funkcí, takže nikdo nebude zkoumat zda už existuje funkce, která řeší jeho problém a rovnou si napíše vlastní. Viz dnešní hrůzy v javascriptu. Nakonec aplikace bude obsahovat funkce jako mojeDPH, mojeLepsiDPH, dphPraveBoty, dphLeveBoty, … No a změnu DPH z 21% na 30% již nebude možno v aplikaci rozumně provést, protože občas a náhodně vám aplikace spočítá špatnou cenu :-))) Namítnete, že toto samé se děje i v OOP jen pomocí jiných prostředků, ano, ale systém napsaný v FP paradigmatu takto degraduje mnohem rychleji než napsaný v OOP paradigmatu, protože funkce map, filter a reduce k tomu přímo vybízejí, naproti tomu OOP má v sobě zabudovanou přirozenou zpětnou vazbu, která tomu brání – dnes opomíjená a zavrhovaná dědičnost.

FP má smysl, ale jedině, když modelovaný systém nejprve modelujete pomocí kategorií, a ty teprve jen implementujete v FP paradigmatu. FP má smysl v paralelním prostředí, kdy naopak umožňuje logicky přirozeně rozdělit výpočet, díky neměnnosti datových struktur. FP bude mít význam pro autonomně uvažující stroje, protože program v FP paradigmatu je možno chápat jako data a tak vytvářet samomodifikující se programy.

Olah

Váš příklad s DPH se v FP dá řešit třeba funkcemi vyšších řádů.

Taco

V praxi to vypadá tak, že:

Ve FP vytvoříme tucet různých funkcí dělající to samé. Pak přijde senior a profackuje vývojáře, kteří projdou všechny ty funkce, a zrefaktorují je. A protože funkce je jednoduchá a kompaktní jednotka, ideálně bez stavů, tak to jde snadno.

V OOP se vytvoří tucet různých metod a tříd, ideálně velice sofistikovaně poděděných (to, že by v praxi dědičnost jakkoliv pomáhala, natož aby byla pozitivní zpětnou vazbou – je mýtus). Následně přijde senior, a začne se chytat za hlavu, a že potřebuje alespoň týden, aby to rozmotal, a dva aby se to otestovalo.

Já nevím, že jsou lidi, kteří mají dar fakt netrefit skutečné problémy FP a výhody OOP a střílejí takhle mimo.

Dědičnost a rozhraní jsou právě ty zmiňované kategorie. S OOP to nesouvisí, a vývojáři to neumí používat. Takže sorry, prostě mýtus.

Dor

A není to také tím, že když někdo dneska programuje funkcionálně, tak je to pravděpodobně člověk, který k oboru přistupuje s jiným očekáváním, než někdo, kdo posledních deset let programoval v javě s tím, že učit se novou technologii se finančně nevyplatí, protože by mu nepomohla vydělal tolik, kolik ho stála ušlá příležitost, když se to učil? Jednoduše řečeno: někdo, kdo hledá práci, kde se programuje funkcionálně, je úplně jiný srdcař, než programátor z ekonomky a dá se čekat, že jeho kód bude vždycky snáze refaktorovatelný, protože přemýšlí nad efektivitou práce jinak.

Taco

Tak to je pěkný argument. Může být.

Palo

Suhlasim s vami. Aj objektove jazyky maju metody a maju aj closure. A to je to co potrebujeme. Celkova struktura aplikacie silne OOP. Male funkcie ktore iterativne prechadzaju rozne cykly napisane v closures.
Dakujem, cisty JavaScript je odpad.

no

Jestli ona ta úspěšnost JS není dána tím, že podporuje DOM operace, běží u klienta a podporuje ho každý, než tím, jaký je to tak „skvělý“ jazyk.
Nehledě na to, že se volá po skutečných OOP prvcích do JS. Protože ono třeba to zapouzdření není jen nějaká hovadina ale skutečně se využívá, aby nikdo „global“ nehrabal kam nemá a takový „odborný“ zásah pak hledat v 100 MB projektu fultextem stojí za to ….
Podle mne je to jenom dnešní móda lidi otrávených z OOP a těch, kteří OOP ani neznají. A sekvenční programování, byť zabalené do funkcí jako JS do „object“, už tu bylo a místo do objektů se budou funkcionality shlukovat do funkcí. No to je revoluce. Spíš mi připadne zajímavé, že s tím přichází nová správa paměti a nové možnosti kompilace.
Ale uvidíme, jak se to rozjede. Nakonec o tom rozhodne hlavně podpora v nasazení a to, kolik nadšenců to bude prosazovat.

pavel

Souhlasím s Vámi. Bude to tím, že prostě v prohlížeči není nic jiného k dispozici, než JavaScript. Být tam Python/Perl/Ruby, tak si myslím, že JavaScript nemá šanci.

noname

Ano, proto je pyjamas tak popupární! Nebo gwt! A proto se prosadil Dart!

nod

Aha a na co svedes uspech Node.js na serverech, kde je tezka konkurence? A proc se prosazuje i v oblastech jako mobilni aplikace (React Native – napr appka Facebooku), desktopove aplikace (napr Spotify, Atom, Visual Code), hardware… ?

tisonet

Ta ukázka kódu je motivační nebo odstrašující příklad toho jak psát funkcionální kód? Rozhodně to není pěkný příklad funkcionálního kódu z pohledu čitelnosti.

clpx

Ja jsem vlezl do komentářů, jen abych si ověřil, ze na toto někdo upozorňuje.

Ten kód je absolutní nečitelná, nezpravovaténa a neefektivni tragédie a jestli má sloužit jakou ukázka vhodnosti FP, tak fakt nevim.

Martin Hassman

Spadl mi kámen ze srdce, když mi došlo, že ten kód jako ukázka vhodnosti FP sloužit nemá. Protože v opačném případě by to mohla být už vážně tragédie. 8-)

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.