Blog | Dependency Injection a funkcionální programování

Dependency Injection a funkcionální programování

Jedna z věcí, bez které bych se v OOP už nechtěl obejít, je Dependency Injection a k němu pohodlně použitelný container. Zato když programuju funkcionálně, obvykle žádný DI container nemám a spravuju si závislosti ručně. Otázkou je proč?

V OOP předáváte pomocí DI objekty.

Ve FP nic takového není, tam máte pouze data a funkce. Jednotkou výpočtu budou obvykle funkce (byť u Lispů se rozdíl mezi daty a funkcemi může smývat). Takže cílím na funkce, které by mohly být předávány pomocí DI.

Možností realizace je více. Z hlavy mě napadají 2. Ukážu „naplnění závislostí“ v místě, ale stejně tak by to mohl udělat i container.

1) Partial Application

(defn x-proto [a b c y] (a (b (c y)))))
(defn x (partial x-proto fn1 fn2 fn3))

(x 5)

2) Parametry s default hodnotou

(defn x [y & {:keys [a b c] :or {a fn1 b fn2 c fn3}}]
        (a (b (c y)))))

(x 5)

Je ale otázkou, zda je nutné předávat pomocí DI úplně všechny parametry. Předáváte si v OOP svou vlastní implementaci funkce +?

Pokud to nevynutí okolnosti, nemusíte ve funkcionálním programování předávat pomocí DI ty funkce, které mají přirozeně 1 implementaci. Dál nemusíte předávat ty funkce, které už jako parametr funkce přijdou.

Pro účely testovatelnosti byste měli oddělit funkce se side-effecty a ty bez nich. Oddělte je tak, že funkce se side-effecty volají funkce bez nich.

Poté, co se snažím aplikovat tato pravidla, se mi ještě nestalo, že bych DI potřeboval. Nechci ale tvrdit, že DI není potřeba vůbec. Na to programuju ve funkcionálním programování až moc krátce.

Realitou je, že věci, které bych v OOP už považoval za prasárnu, jsou v FP dobře čitelné a udržovatelné.

(defn somefn [arg1]
        (udelej-neco arg1)
        (timbre/info "Somefn called" arg1)
        (udelej-tamto arg1))

Timbre je nástroj na logování, správně by měl být předán zvenčí, pokud bychom používali OOP. Vlastně psát aplikaci objektově, ani by mě nenapadlo nic jiného, než vždy všude za každých okolností všechny závislosti získávat z DI containeru. Kdybych v dané funkci potřeboval mít možnost vyměnit logování, upravil bych funkci takto (a tam, kde bych chtěl jinou logovací funkci, předával bych ji):

(defn somefn [arg1 & {:keys [logfn] :or {logfn timbre/info}}]
        (udelej-neco arg1)
        (logfn "Somefn called" arg1)
        (udelej-tamto arg1))

Takové řešení má samozřejmě všechny nevýhody toho, kdy si závislosti v OOP sami vytváříte v construktoru, pokud nejsou předány zvnějšku.

Proto je pro mě záhadou, proč ve FP lidé DI nepoužívají a zdá se, že jim ani nechybí. Že by byla komunita FP zabržděná? Pochybuju, mám zkušenost, že když už se člověk o FP začne zajímat, je to projevem toho, že je dobrý programátor a že vývoji SW rozumí.

Jenže co když je špatná myšlenka dávat do DI všechno, všude, za jakýchkoliv podmínek? Taková implementace by ve FP byla nepraktická a v 99 % případů by container jen předával přesně 1 funkci, která se v dané situaci hodí použít. Co kdybych vyseknul jen ty věci, kde je potřeba ty věci předávat?

A co když jsou to zrovna ty věci, které už dostanu z běžného toku programu? Tohle se mi ve FP děje a já zatím nechápu proč.

A co když v OOP je taky zbytečné dávat do DI containeru všechno?

Co myslíte vy? Jaký máte postoj k DI containerům? A co do DI containeru dát a co ne? Dali byste tam i funkci +?

Programování

Předejte zkušenosti i dalším a sdílejte tento článek!



Jiří Knesl
Business & IT konzultant

Jiří Knesl poprvé začal programovat v roce 1993. Od té doby, díky skvělým učitelům a později zákazníkům, měl možnost neustále růst v oboru vývoje webových aplikací a informačních systémů. v roce 2002 se přidal zájem o ekonomii a v roce 2006 o organizaci práce. Vším tím se konstantně profesně zabývá jak ve svém podnikání, tak i u zákazníků. Za posledních 5 let vydal na tato témata přes 400 článků.

Prohlédněte si moje reference

Mám zkušenosti z rozsáhlých projektů pro korporace, velké podniky, střední i malé firmy, ale i pro startupy v cloudu. Zvyšoval jsem jejich know-how, pomáhal nastavovat jejich organizační strukturu, byl lektorem a mentorem v náročných situacích. Podívejte se, jak vidí můj přínos samotní klienti.

Sledujte mé postřehy na sociálních sítích