Voitko välttää toiminnallisen ohjelmoinnin käytännöksi?

Säännöt: Nick Youngson CC BY-SA 3.0 Alpha Arkistokuvat

Funktionaalinen ohjelmointi on tunkeutunut suurimpaan osaan valtavirtaista ohjelmointimaailmaa - suuri osa JS-ekosysteemistä, Linq for C #, jopa Java: n korkeamman asteen toiminnoista. Tämä on Java vuonna 2018:

getUserName (käyttäjät, käyttäjä -> user.getUserName ());

FP on niin hyödyllinen ja kätevä, että se on löytänyt tiensä jokaiseen nykyaikaiseen ohjelmointikieleen, jota voin ajatella.

Mutta se ei ole kaikkia sateenkaareja ja pentuja. Monet kehittäjät kamppailevat tämän tektonisen muutoksen kanssa ajattelumme ohjelmistoista. Suoraan sanottuna, tänään on vaikea löytää JavaScript-työtä, joka ei vaadi mukavuutta toiminnallisten ohjelmointikonseptien kanssa.

FP on kummankin hallitsevan kehyksen ydin, React (jaetun muuttuvan DOM: n välttäminen on sen arkkitehtuurin ja yksisuuntaisen tiedonkulun motivaatio) ja kulma (RxJS on verkkoyhtiöiden kirjasto, joka toimii virroissa korkeamman - tilaustoiminnot - sitä käytetään laajasti koko kulma-alueella). Redux ja ngrx / store myös: toimivat molemmissa tapauksissa.

Toiminnallinen ohjelmointi voi olla pelottava aihe lähestymistavalle kehittäjille, jotka ovat siihen uusia, ja nopean sisäänpääsyn vuoksi joku tiimisi jäsenistä voi ehdottaa, että helpotat ryhmääsi sopeutumaan koodipohjaan välttämällä FP: tä politiikkana.

Johtajalle, joka ei tunne FP: tä tai sen leviämistä nykyaikaisessa koodiekosysteemissä, se saattaa kuulostaa järkevältä ehdotukselta. Loppujen lopuksi, eikö OOP palvellut ohjelmistomaailmaa hyvin 30 vuoden ajan? Miksi et jatka niin tekemistä?

Nauti viihdyttämästä tätä ajatusta hetkeksi.

Mitä edes tarkoittaa "kieltää" puiteohjelma politiikkana?

Mikä on toiminnallinen ohjelmointi?

Lempimäärittelyni toiminnallisesta ohjelmoinnista on seuraava:

Funktionaalinen ohjelmointi on ohjelmointiparadigma, joka käyttää puhtaita funktioita koostumuksen atomiyksikkönä välttäen jaettuja muuttuvia tiloja ja sivuvaikutuksia.

Puhdas funktio on funktio, joka:

  • Samaa tuloa käytettäessä palauta aina sama lähtö
  • Ei haittavaikutuksia

FP: n ydin on todella seuraava:

  • Ohjelma toimintojen kanssa
  • Vältä jaettuja muuttuvia tila- ja sivuvaikutuksia

Kun laitat ne yhteen, saat ohjelmistokehityksen käyttämällä puhtaita toimintoja rakennuspalikoina (”koostumuksen atominen yksikkö”).

Kaiken nykyaikaisen OOP-aloitteen tekijän Alan Kayn mukaan OOP: n ydin on:

  • kapselointi
  • Viesti kulkee

Joten OOP on vain yksi tapa välttää jaettuja muuttuvia tiloja ja sivuvaikutuksia.

On selvää, että FP: n vastakohta ei ole OOP. FP: n vastakohta on jäsentämätön, proseduuriohjelmointi.

Smalltalk (jossa Alan Kay loi OOP: n perustan) on sekä olio- että toiminnallisuus, ja ajatus yhden tai toisen valinnasta on täysin vieras ja käsittämätön.

Sama pätee JavaScriptiin. Kun Brendan Eich palkattiin rakentamaan JavaScript, ideat olivat:

  • Järjestelmä selaimessa (FP)
  • Näyttää Java (OOP)

JavaScript-ohjelmassa voit yrittää suosia yhtä tai toista, mutta paremmiksi tai huonommiksi ne on liitetty erottamattomasti toisiinsa. Kapselointi JavaScriptiin perustuu sulkemiseen - käsite toiminnallisesta ohjelmoinnista.

Mahdollisuudet ovat erittäin hyvät, jo suoritat jo toiminnallista ohjelmointia, tiedätkö sen tai et.

Kuinka EI tehdä FP: tä

Toiminnallisen ohjelmoinnin välttämiseksi joudut välttämään pelkkien toimintojen käytön. Ongelmana on, että nyt et voi kirjoittaa tätä, koska se saattaa olla puhdasta:

const getName = obj => obj.name;
const name = getName ({uid: '123', nimi: 'Banksy'}); // Banksy

Katsotaanpa niin, että se ei ole enää FP. Voisimme sen sijaan tehdä siitä luokan, jolla on julkinen omaisuus. Koska siinä ei käytetä kapselointia, soitetaan tälle OOP: lle. Ehkä meidän pitäisi kutsua tätä "prosessiobjektiohjelmointiksi" ?:

luokan käyttäjä {
  rakentaja ({nimi}) {
    tämä.nimi = nimi;
  }
  getName () {
    palauta tämä nimi;
  }
}
const myUser = uusi käyttäjä ({uid: '123', nimi: 'Banksy'});
const name = myUser.getName (); // Banksy

Onnittelut! Olemme juuri muuttaneet 2 koodiriviä 11: ksi ja ottaneet käyttöön hallitsemattoman, ulkoisen mutaation todennäköisyyden. Mitä olemme saaneet?

No, ei mitään. Itse asiassa olemme menettäneet paljon joustavuutta ja mahdollisuuden merkittäviin säästöihin koodilla.

Edellinen getName () -toiminto toimi minkä tahansa syöttöobjektin kanssa. Tämäkin tekee (koska se on JavaScript ja voimme delegoida menetelmiä satunnaisiin objekteihin), mutta se on paljon hankalampaa. Voisimme antaa kahden luokan periä yhteisestä perusluokasta - mutta se merkitsee suhteita, joita ei välttämättä tarvitse olla objektiluokkien välillä lainkaan.

Unohda uudelleenkäyttö. Olemme juuri huuhtaneet sen viemäriin. Koodin päällekkäisyys näyttää tältä:

luokkaystävä {
  rakentaja ({nimi}) {
    tämä.nimi = nimi;
  }
  getName () {
    palauta tämä nimi;
  }
}

Hyödyllinen opiskelija soittaa huoneen takaa:

"Luo tietysti henkilöluokka!"

Mutta toisaalta:

luokan maa {
  rakentaja ({nimi}) {
    tämä.nimi = nimi;
  }
  getName () {
    palauta tämä nimi;
  }
}
”Mutta ilmeisesti nämä ovat erityyppisiä. Tietysti et voi käyttää henkilömenetelmää maassa! "

Jolle vastaan: "Miksi ei?"

Yksi toiminnallisen ohjelmoinnin hämmästyttävistä eduista on triviaalia helppo yleinen ohjelmointi. Saatat kutsua sitä ”yleiseksi oletuksena”: Kyky kirjoittaa yksi toiminto, joka toimii minkä tahansa tyyppisen kanssa, joka täyttää sen yleiset vaatimukset.

Huomaa: Java-ihmisille tämä ei koske staattisia tyyppejä. Joillakin FP-kielillä on loistavat staattisen tyyppiset järjestelmät, ja ne jakavat tämän hyödyn silti ominaisuuksilla, kuten rakenteellisilla ja / tai korkeammalle tyypeille.

Tämä esimerkki on triviaalia, mutta säästöt koodimäärissä, jotka saamme siitä tempusta, ovat monumentaalisia.

Sen avulla autodux-kaltaiset kirjastot voivat luoda verkkotunnuksen logiikan automaattisesti jokaiselle kohteelle, joka koostuu getter / setter-pareista (ja paljon muuta, paitsi). Pelkästään tämä temppu voi katkaista verkkotunnuksesi logiikan koodin puoleen tai parempaan.

Ei enää korkeamman asteen toimintoja

Koska useimmat (mutta eivät kaikki) korkeamman asteen funktiot hyödyntävät puhtaita funktioita palauttaaksesi samat arvot samoihin tuloihin, et voi käyttää myös sellaisia ​​toimintoja kuin .map (), .filter (), pienentä () ilman heittää sivuvaikutuksen sanoen, että et ole puhdas:

const arr = [1,2,3];
const double = n => n * 2;
const doubledArr = arr.map (kaksinkertainen);

saadaan:

const arr = [1,2,3];
const double = (n, i) => {
  console.log ('Satunnainen sivuvaikutus ilman syytä.');
  console.log (`Voi, tiedän, voisimme suoraan tallentaa tulosteen
tietokantaan ja kytkeä verkkotunnuksen logiikka tiukasti I / O-järjestelmään. Se tulee olemaan hyvä. Kenenkään muun ei tarvitse kertoa kahdella, eikö? ");
  saveToDB (i, n);
  paluu n * 2;
};
const doubledArr = arr.map (kaksinkertainen);

RIP, toimintakoostumus 1958–2018

Unohda korkeamman asteen komponenttien pistemätön koostumus koteloidaksesi monialaiset huolenaiheesi sivuilla. Tämä kätevä, deklaratiivinen syntaksi on nyt rajoittamaton:

const wrapEveryPage = kirjoita (
  withRedux,
  withEnv,
  withLoader,
  withTheme,
  withLayout,
  withFeatures ({alkuperäinenFeatures})
);

Jokainen niistä täytyy tuoda manuaalisesti jokaiseen komponenttiin tai, mikä pahempaa - laskeutua sotkeutuvaan, joustamattomaan luokanperintöhierarkiaan (jota OO: n suunnittelukanonki pitää oikein anti-mallina useimmissa terveellisissä olosuhteissa, jopa [varsinkin?]) ).

Jäähyväiset, lupaukset ja asynk / odottaa

Lupaukset ovat monadeja. Teknisesti kategoriateoriasta, mutta kuulen myös olevan FP-asia, koska Haskellillä on ne ja hän tekee monadeista kaiken puhdasta ja laiskaa.

Rehellisesti sanottuna monadien ja functor-opetusohjelmien menettäminen on todennäköisesti hyvä asia. Nämä asiat ovat niin paljon helpompia kuin me teemme niistä ääniä! On syytä opettaa ihmisille käyttämään Array.prototype.map ja lupauksia, ennen kuin esitän funktorien ja monadien yleiset käsitteet.

Tiedätkö kuinka niitä käytetään? Sinulla on enemmän kuin puolimatka funktorien ja monadien ymmärtämiseen.

Joten välttääkseen FP: tä

  • Älä käytä JavaScriptin suosituimpia kehyksiä tai kirjastoja (ne kaikki pettävät sinut FP: lle!).
  • Älä kirjoita puhtaita toimintoja.
  • Älä käytä paljon JavaScriptin sisäänrakennettuja ominaisuuksia: Suurin osa matematiikan toiminnoista (koska ne ovat puhtaita), ei-mutatoivia merkkijono- ja matriisimenetelmiä, .map (), .filter (), .forEach (), lupaukset, tai asynk / odota.
  • Älä kirjoita turhia luokkia.
  • Tuplaa (tai useampi) verkkotunnuksesi logiikka kirjoittamalla mantereille ja asettajille käsin kaiken.
  • Suorita "luettava, selkeä" välttämätön lähestymistapa ja sitoa verkkotunnuksesi logiikka renderointiin ja verkko I / O-huolenaiheisiin.

Ja hyvästellä:

  • Aikamatkan virheenkorjaus
  • Helppo kumoa / tee uudelleen ominaisuuksien kehitys
  • Kestävä, johdonmukainen yksikkötesti
  • Mock ja D / I ilmainen testaus
  • Nopeat yksikkötestit ilman riippuvuuksia verkon I / O: sta
  • Pienet, testattavat, virheenkorjattavat, ylläpidettävät koodit

Vältä toiminnallista ohjelmointia politiikkana? Ei ongelmaa.

Hei odota.

Lisätietoja EricElliottJS.com

EricElliottJS.com: n jäsenille on tarjolla videotunteja toiminnallisesta ohjelmoinnista. Jos et ole jäsen, kirjaudu tänään.

Eric Elliott on kirjoittanut ”Programming JavaScript Applications” (O’Reilly) -kirjailijan ja ohjelmiston ohjausalustan, DevAnywhere.io, perustaja. Hän on osallistunut ohjelmistokokemuksiin Adobe Systemsille, Zumba Fitnessille, The Wall Street Journalille, ESPN: lle, BBC: lle ja parhaille äänittäjille, mukaan lukien Usher, Frank Ocean, Metallica ja monille muille.

Hän työskentelee etäällä mistä tahansa maailman kauneimman naisen kanssa.