Zobrazují se příspěvky se štítkemJavascript. Zobrazit všechny příspěvky
Zobrazují se příspěvky se štítkemJavascript. Zobrazit všechny příspěvky

neděle 18. března 2018

Jak psát stabilní kód v JavaScriptu?

Pokud se rozhodnete, že v JavaScriptu napíšete větší část kódu, tak narazíte na to, že bez podpůrných nástrojů se z této cesty může stát peklo. Existuje velké množství vývojářů, kteří Vám řeknou, že JavaScript je bastl a nedá se v něm smysluplně napsat nic jiného, než pár drobností na rozhýbání webu. Opak je pravdou. V současné době je JavaScript nejuniverzálnějším jazykem na světě.

Je vcelku jedno, zda v JavaScriptu píšete aplikace typu backend, web, mobil, desktop, příkazy pro konzoli či třeba cloud funkce. Stále byste se měli snažit o to, abyste svůj kód zapsali tím nejlepším možným způsobem.

JavaScript se za posledních několik let výrazně změnil. Dostali jsme se do stavu, kdy existují dvě skupiny programátorů.

První skupinou jsou ti, kteří ignorují nové ECMAScript specifikace a JavaScript zapisují "starým způsobem". Do této skupiny často spadají lidé, kteří potřebují občas rozhýbat určitou část webu a JavaScript chápají jako jazyk, který přímo vykoná webový prohlížeč. O této skupině vývojářů se dá říci, že vlastně neumí v současném JavaScriptu programovat.

Druhou skupinou jsou vývojáři, kteří umí využít věci jako je Node.js, Babel, Typescript, apod. Kód v JavaScriptu zapisují v nových ECMAScript specifikacích a fakticky jsou schopni z tohoto jazyka často vytěžit maximum. Jedná se o naprosto jiný svět, než je tomu v případě první skupiny.

Abych Vám toto předal trochu více exaktněji, podívejte se na následující příklad, který ilustruje rozdíl mezi první a druhou skupinou:
// prvni skupina
function oldWay(options) {
    return {
        name: options.name,
        hello: function () {
            return 'Hello ' + options.name;
        }
    }
}

// druha skupina
const newWay = ({name}) => ({name, hello: () => `Hello ${name}`});

console.log(oldWay({name: 'Old way'}).hello());
console.log(newWay({name: 'New way'}).hello());

Tento kód je založen na využití arrow functions, string interpolation a destructuring assignment. Věřte, že je to jen část vlastností, které nové ECMAScript specifikace nabízí. Teď ruku na srdce, pokud je zde čtenář té první skupiny, poznal by, že ten druhý zápis ve výsledku dělá tu samou věc? Na JavaScript se dá koukat jako na dva jazyky. Na jazyk před ECMAScript 6 a jazyk s ECMAScript 6 a vyšší.

Ale pojďme zpět. Jak zajistit to, abychom v JavaScriptu byli schopni psát stabilní kód, který se nám nerozsype s novou posilou v týmu či tím, že někdo bude psát "starým" a někdo "novým" způsobem?

Airbnb JavaScript Style Guide

První věcí, kterou by každý JavaScript programátor měl začít je, že si přečte a osvojí si style guide, tedy zápis JavaScript kódu. K tomtu účelu se výborně hodí následující příručka Airbnb JavaScript Style Guide.
Dokud si toto neosvojíte, těžko se můžete považovat za seniornějšího JavaScript programátora.

Typescript / Flow

Pokud to s JavaScriptem myslíte skutečně vážně, určitě byste se měli snažit o to, abyste tento jazyk obohatili o statickou typovou kontrolu. Jelikož je JavaScript dynamicky typovaný jazyk, tak v případě, že se Vám projekt v JavaScriptu rozšíří, tak bez typové kontroly je jakýkoli refactoring roven ruské ruletě. Osobně preferuji Typescript a důvody proč, jsem sepsal v článku Proč právě Typescript.

Typescript strict mode

Součástí Typescriptu je i možnost nastavení striktního módu. Toto nastavení se jmenuje přímo "strict". Co se díky tomutu módu vše zapne, najdete v manuálu: https://www.typescriptlang.org/docs/handbook/compiler-options.html

ESLint / TSLint

Další nezbytnou součástí je ESLint (v Typescriptu TSLint). Linting, nebo-li "lustrování" kódu slouží k tomu, aby Vám nadával za to, že jste kód nezapsali zrovna tím nejlepším způsobem. Například Vám řekne, že jste napsali function, místo toho, abyste použili arrow function, že jste string zapsali ve špatných uvozovkách, že jste překročili limit počtu znaků na řádku, apod.
I když možná budete tento linter na začátku nenávidět, tak věřte, že je to dočasné. Časem totiž poznáte, že je to velice dobrý sluha. Dá se říci, že Vás naučí správně zapisovat JavaScript kód.

Prettier

Dalším skvělým pomocníkem je Prettier. Tento nástroj slouží k tomu, že za Vás automaticky formátuje kód. K čemu je to vlastně dobré?
Osobně pracuji tak, že když píšu kód, tak automaticky stále spouštím dvě základní operace nad kódem: "Format code & Optimize imports". Dělám to tak už roky a jsem přesvědčen, že by toto měl dělat každý vývojář. Každý moderní vývojový nástroj (Atom, WebStorm, Visual Studio Code, apod) má tyto dvě operace k dispozici.
Ve chvíli, kdy pracuji na projektu, kde je více lidí, tak bez automatického formátu vzniká problém. Co dokáže naprosto otrávit je, když automaticky formátujete kód jen v editoru a najednou uděláte změny i tam, kde jste vůbec nepracovali. Git Vám poté hlásí, že poslední změnu na daném řádku jste udělali Vy a přitom to není vůbec pravda.
První variantou je, že všem vývojářům přikážete, že musí používat jedno IDE a jeden styl formátování. A věřte, to je to poslední, co chcete dělat. Ne každý chce třeba psát kód v IntelliJ IDEA. Proto zde máme Prettier. Nástroj, který za nás určí pravidla a vy se jim automaticky přizpůsobíte, ať už píšete v poznámkovém bloku či třeba v Atomu.
Druhou důležitou vlastností je to, že Prettier Vám formátuje kód tak, aby správně doplnil závorky, středníky, atd, podle jasně definovaného style guide.

Integrace TSLintu a Prettier s Gitem

Nyní se pojďme podívat na to, jak využít TSLint a Prettier při práci s Gitem. Berme v potaz, že již máte projekt v Gitu. Projekt je v Typescriptu a jedná se o React aplikaci.

Nejprve do projektu přídáme závislost na tslint a tslint-react:
npm i -D tslint tslint-react

Poté do projektu přidáme soubor tslint.json:
{
  "extends": [
    "tslint:recommended",
    "tslint-react"
  ],
  "rules": {
    "max-line-length": [
      false,
      160
    ],
    "semicolon": [
      true,
      "always",
      "ignore-bound-class-methods"
    ],
    "quotemark": [
      true,
      "single",
      "jsx-double"
    ],
    "member-ordering": [
      true,
      "variables-before-functions"
    ],
    "ordered-imports": false,
    "interface-name": false,
    "object-literal-key-quotes": [
      true,
      "as-needed"
    ],
    "object-literal-sort-keys": false,
    "no-object-literal-type-assertion": false,
    "no-empty-interface": false,
    "jsx-no-multiline-js": false,
    "jsx-boolean-value": false,
    "member-access": false
  }
}

Do package.json stačí přidat následující skript:
"scripts": {
    "tslint": "tslint -c tslint.json 'src/**/*'"
}

A poté spustit:
npm run tslint
Hlásí Vám tslint chybu? Pokud ano, tak nezbýbá, než ony chyby opravit :)

Nyní pojďme přidat prettier:
npm i -D husky prettier pretty-quick
Současně s knihovnou prettier nainstalujeme knihovnu husky, která slouží k tomu, že vytvoří git hook.

Dále v projektu vytvoříme soubor .prettierrc.json:
{
  "printWidth": 160,
  "tabWidth": 4,
  "parser": "typescript",
  "singleQuote": true,
  "bracketSpacing": false,
  "trailingComma": "all",
  "arrowParens": "always"
}

Jelikož použijeme pretty-quick pro provedení automatického formátování, je třeba definovat soubor .prettierignore, ve kterém určíme adresáře a soubory, které z automatického formátovaní chceme vynechat:
.circleci/
.next/
dist/
package.json
package-lock.json

Poté, co máme základní konfiguraci hotovou, nezbývá, než obohatit náš package.json:
"scripts": {
    "tslint": "tslint -c tslint.json 'src/**/*'",
    "precommit": "pretty-quick --staged && npm run tslint"
}
A nyní stačí zkusit provést commit do gitu :)

Toto řešení je postavené na tom, že používáte Git. Před tím, než se provede samotný commit do Gitu, tak se nejprve spustí formát kódu a poté se překontroluje pomocí TSLintu. Pokud máte něco špatně, commit se neprovede. Pokud Vám nevyhovuje precommit, můžete využít i možnost prepush, tedy před tím, než se provede push do remote git repozitáře. Nicméně výsledkem je, že se Vám do společného Git repozitáře vždy dostane pouze kód, který je spravné formátovaný a zkontrolovaný pomocí linteru.

Kromě Git hooku je určitě vhodné, abyste toto provedli ještě v CI. Tedy ve vašem nástroji na continuous integration. V našem případě se jedná o CircleCI, kde pouze spustíme samotný příkaz npm run tslint a tím zajistíme, že před nasazením na server nemáme v kódu něco špatně.

Závěr

Zajistit štábní kultruru v JavaScript projektech není složitá záležitost. Celé je to pouze o tom, že čím déle budete věci jako je TSLint či Prettier ignorovat, tím víc práce v budoucnu budete mít.
Také je dobré zmínit, že nelze nekriticky spoléhat na tyto nástroje. Stále je pouze na Vás, zda kód, který napíšete je nakonec funkční. Nejsou to nástroje, které Vás například zbaví nutnosti psát unit testy.
A co vy? Používáte některé ze zmíněných nástrojů?

neděle 10. prosince 2017

Vývoj aplikací přes Docker

V dnešní době asi neexistuje vývojář, který by někdy neslyšel o Dockeru. O technologii, která se v posledních letech stala hlavním prostředkem pro moderní vývoj aplikací.

Co je to Docker?

Docker je kontejner, ve kterém běží vaše aplikace. V konečném stavu se jedná o linuxový virtuální server, který obsahuje vše potřebné, co jste si sami definovali. Představte si, že máte Node.js aplikaci, která běží na portu 8080. Takovouto aplikaci můžete velice jednoduše převézt do Dockeru a tu poté nasadit v Cloudu.

Než se pustíme do samotných příkladů, pojďme si nejdříve říci, proč bychom něco takového, jako je Docker vlastně měli chtít.

Proč Docker?

Jednotné prostředí

Vývoj aplikací je často tvořen z několika fází. První fází bude development prostředí, které je určené pro vývojáře. Po určité době se aplikace dostane do stavu testování, kde se provede akceptace, zda je onen softwarový produkt určen pro produkci. Poté dojde k nasazení na prostředí simulující produkci, tedy otestuje se vůči produkčním datům. A nakonec zde máme produkci.

Když to sečteme, zjistíme, že naše aplikace neběží jen na jednom prostředí, ale naopak jsme nuceni, abychom aplikaci jednoduše rozeběhli na více serverech. Každé prostředí by mělo být jednotné a právě s tím nám Docker může pomoci. Díky Dockeru můžeme totiž zajistit, že ono prostředí bude vždy Debian ve verzi x.y, s Node.js ve verzi 8.1 apod.

Lokální vývoj

Samotnou aplikaci musí někdo někde napsat. K tomu nám samozřejmě slouží naše vlastní počítače. A zde je kámen úrazu. Pokud nepoužijeme Docker, tak aplikaci píšeme v prostředí, které je velice často vzdálené produkčnímu prostředí.

Představme si situaci, kdy Pepa používá Windows, Franta má Linux a Jarda jede na MacOS. V takovém případě musíme někam sepsat požadavky typu: "musíte mít Node.js verzi 8.2, musíte mít nainstalovánu technologii A, B, C,....". V případě Dockeru nemusíte. Nemusíte řešit to, kdo jaký má operační systém, kdo jakou má verzi Node.js, apod. A už vůbec nemusíte své vývojáře nutit, aby používali prostředí, které je jim nepřirozené či je složité na nastavení.

Horizontální škálování

Samotná technologie Docker Vám sice neumožňuje používat škálování, ale díky Dockeru se ke škálování můžete snadněji dostat. K tomuto účelu zde existují technologie jako je Kubernetes, Swarm či Mesos. Jedná se o technologie, které běží nad Vašimi dockery a orchestruje jednotlivé kontejnery.

Snažsí nasazení

Pokud přejdeme na myšlenku Dockeru, který říká: "Nasazuj aplikace z předem připravených kontejnerů", tak nám tím současné říká: "Nestarejte se tolik o to, jak konfigurovat server". S tím práve souvisí i to, jak aplikaci nakonec nasadit. V případě, že máte vlastní virtuální či fyzický server, často se z deploymentu stává černá díra, protože nasadit aplikaci umí jen infra tým, popřípadě ten nejšikovnější programátor, který je i administrátorem. Nasazení pomocí Dockeru totiž nakonec může znamenat, že postup se zredukuje na 1 až 2 řádky kódu (docker registr -> server). Většina Cloudových řešení, jako je Azure, AWS či Google Cloud, Vám totiž nabízí možnost, jak jednoduše takové nasazení z Docker image provést.

Node.js a Docker

Nyní se již pojďme podívat na ukázku, jak použít Docker při vývoji Node.js aplikací.

Pro následující ukázky budete potřebovat:
  1. Node.js 8 a vyšší (pro inicializaci projektu, v budoucnu se nejedná o běhové prostředí aplikace)
  2. Docker
  3. Editor kódu (WebStorm, Atom, Visual Studio Code, apod)
Představme si, že máme jednoduchou Node.js aplikaci, která na portu 8080 vrací "Hello World". Jednoduchý návod na vytvoření takove aplikace by byl následující:

Inicizalizace projektu:
npm init

Instalace závislostí:
npm install express

Soubor src/index.js:
const express = require('express');
const app = express();

app.get('/', (req, res) => {
    res.send('Hello world!');
});

app.listen(8080, () => {
    console.log('Running on http://localhost:8080');
});

Aplikaci bychom spustili následujícím příkazem:
node src/index.js

V prohlížeči by nyní na adrese http://localhost:8080 měla běžet naše aplikace. Nyní aplikaci zastavme a pojďme ji převést do Dockeru.

Dockerizování

V kořenovém adresáři projektu vytvořte soubor Dockerfile:
FROM node:carbon

MAINTAINER Ales Dostal <a.dostal@apitree.cz>

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install

# Bundle app source
COPY . /usr/src/app

EXPOSE 8080
CMD ["node", "src/index.js"]

Na prvním řádku definuje image, ze kterého budeme vycházet. V našem případě to je node:carbon, což je Node.js verze 8.x. Pokud chcete definovat přesnou verzi Node.js můžete použít například node:8.9.3. Pokud nevíte, jake obrazy jsou k dispozici, není nic jednoduššího, než se podívat na Docker Hub.

Klauzule MAINTAINER je pouze informativní, nicméně je jistě dobré jí definovat, aby samotný image obsahoval metadata o tom, kdo daný image vytvořil a kdo je jeho vlastníkem.

Poté již konkrétně definujeme, co náš Docker image obsahuje. Nejprve vytvoříme adresář /usr/src/app a ten nastavíme jako výchozí adresář. Výchozí při běhu Dockeru.

Dále do výchozího adresáře překopírujeme package.json a spustíme instalaci závislostí.

Posledním příkazem, který se spouští při vytváření Docker image, je překopírování celého projektu do výchozího adresáře.

Na konci je ještě definování portu, který bude z běžícího Dockeru viditelný a také příkaz, který se spustí vždy, když Docker image spustíme. V tom je hlavní rozdíl mezi klauzulí RUN a CMD. V našem případě je to příkaz node src/index.js.

Poslední částí je vytvoření souboru .dockerignore:
node_modules

Do tohoto souboru definujeme adresáře a soubory, které se mají při vytváření docker image ignorovat. V našem případě je to například node_modules, protože tento adresář, který obsahuje závislosti, si docker vytvoří sám (díky RUN npm install).

Vytvoření Docker image

Nyní již nic nebrání tomu, vytvořit si na lokálním stroji vlastní docker image. K tomuto účelu stačí spustit tento příkaz:
docker build -t apitreecz/testapp .

Pozor, nezapoměnte na konci na onu tečku. Jde o to, že tento příkaz spouštíme v kořenovém adresáři projektu a tou tečkou určujeme adresář, kde příkaz docker bude hledat projekt a hlavně soubor Dockerfile a .dockerignore.

Samotný příkaz začně stahovat image node:carbon a současně spustí příkazy jako npm install a kopírování projektu do /usr/src/app (samozřejmě v Dockeru, nikoli ve vašem stroji).

Poté, co příkaz doběhne, měl by napsat něco jako:
Successfully built 46aaa661cef4
Successfully tagged apitreecz/testapp:latest

Abychom se přesvědčili, že náš docker image skutečně existuje, stačí se podívat pomocí příkazu:
docker images

Výstup by měl vypadat nějak takto:
REPOSITORY                    TAG                 IMAGE ID            CREATED             SIZE
apitreecz/testapp             latest              46aaa661cef4        2 minutes ago       751MB

Díky tomu máme ve svém lokálním repozitáři vytvořen Docker image, který stačí jen spustit.

Spuštění Docker image

Pro spuštění docker image stačí následující příkaz:
docker run -p 8080:8080 -d apitreecz/testapp

Pokud jste vše udělali správně, měla by Vaše aplikace běžet na portu 8080. Takže nezbývá, než v browseru vyzkoušet spustit http://localhost:8080.

Abyste byli schopni vůbec sledovat, co se s Vaší aplikací v Dockeru děje, pojďme se podívat na pár příkazů, které Vám můžou pomoci.

Výpis běžících docker kontejnerů:
docker ps

Výstup by měl vypadat nějak takto:
CONTAINER ID        IMAGE               COMMAND               CREATED             STATUS              PORTS
e9321555c9cc        apitreecz/testapp   "node src/index.js"   6 seconds ago       Up 2 seconds        0.0.0.0:8080->8080/tcp

V této chvíli je pro nás duležitý CONTAINER_ID, kterým se daný bežící Docker kontejner identifikuje.

Logy Docker kontejneru:
docker logs <container id>

Vstup do konzole Docker kontejneru:
docker exec -it <container id> /bin/bash

Zastavení Docker kontejneru:
docker stop <container id>

Pokud jste se úspěšně dostali až sem, dá se říci, že máte první krok k "dokerizaci" za sebou. Naučili jsme se, jak vytvořit Docker image, jak daný Docker image spustit, spravovat a nakonec jak ho i zastavit.

Nyní se pojďme podívat na další bod a tím je vývoj vůči Docker kontejneru.

Vývoj na běžícím Docker kontejneru

Jistě jste si všimli, že pokud bychom chtěli vyvíjet aplikaci pomocí Dockeru, tak současný postup by pro nás znamenal: zastavit kontejner, napsat kód, vytvořit kontejner, spustit kontejner. Tento postup by byl samozřejmě možný, ale zároveň i dost zdlouhavý. Proto si pojďme udělat ukázku, jak toto vyřešit elegantnějším zpusobem.

Docker a Next.js

Pro účely ukázky použiji Next.js, který umožňuje hot reload, díky kterému si lépe můžeme ukázat, jak vyvíjet na běžícím docker kontejneru, který bude reagovat na naše změny.

Prvním krokem bude vytvoření jednoduché Next.js aplikace.

Nejprve vytvoříme adresář nextjsdemo a do něj přejdeme:
mkdir nextjsdemo
cd nextjsdemo

Dále provedeme inicializaci pomocí npm:
npm init

Po odklikání všech otázek se nám v projektu vytvoří package.json.

Dále nainstalujeme potřebné závislosti:
npm install --save next react react-dom

Nyní vytvoříme soubor pages/index.js:
export default () => <div>Hello from Next.js!</div>

Poslední částí je zápis scripts do package.json:
  "scripts": {
    "dev": "next",
    "build": "next build",
    "start": "next start"
  }

Teď už nic nebrání tomu, abychom si svojí aplikaci zkusili spustit:
npm run dev

Na portu 3000 poběží naše aplikace. Pro test stačí v browseru spustit: http://localhost:3000. Pokud jste vše udělali správně, měli byste vidět webovou stránku s "Hello from Next.js!". Při přepsání textu v pages/index.js, můžete vidět, že díky Next.js máte k dispozici hot reload a hned v browseru vidíte samotnou změnu. Aplikaci zastavte a pojďme ji "dokerizovat".

Nyní vytvoříme Dockerfile, který nám opět bude definovat docker image:
FROM node:carbon

MAINTAINER Ales Dostal <a.dostal@apitree.cz>

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Install app dependencies
COPY package.json /usr/src/app/
RUN npm install

# Bundle app source
COPY . /usr/src/app

RUN cd /usr/src/app && npm run build

EXPOSE 3000
CMD ["npm", "start"]

Jedná se o velice podobný soubor, který jsme tvořili v první ukázce, pouze zde přidáváme build samotné aplikace a port, na kterém aplikace bude vystupovat je 3000. Samozřejmě port lze změnit i na 8080, pouze bychom doplnili parametr k npm start, na kterém portu se má Next.js aplikace spustit.

Dále opět vytvoříme také soubor .dockerignore:
.next
node_modules

V .dockerignore opět definujeme všechny adresáře a soubory, které nechceme do docker image kopírovat. Tím, že jsme si zkoušeli aplikaci již pustit, můžete si všimnout, že nám Next.js vytvořil adresář .next, který ale z lokálního stroje nechceme kopírovat, protože si ho image vytvoří sám.

Opět vytvoříme docker image:
docker build -t apitreecz/nextjsdemo .

Pro kontrolu si můžeme zkusit náš docker spustit:
docker run -p 8080:3000 -d apitreecz/nextjsdemo

Pokud jste vše udělali správně, měli byste ve webovém prohlížeči, na adrese http://localhost:8080 vidět naší aplikaci. Zde si můžete všimnout, že i když aplikace v Docker kontejneru běží na portu 3000, my jsme jí přemapovali na port 8080 pro náš lokální stroj.

Nicméně nyní jsme ve stavu, kdy nám kontejner spustil aplikaci v produkčním módu (díky npm start) a zároveň nemáme možnost docker image aktualizovat.

Abychom byli schopni za běhu náš běžící Docker kontejner aktualizovat, použijeme k tomu Docker Compose. Nejprve zastavte původní Docker kontejner a pojďme se podívat jak na to.

V root adresáři vytvoříme soubor docker-compose.yml:
version: "2"
services:
  webapp:
    build: .
    command: npm run dev
    ports:
      - "8080:3000"
    volumes:
      - .:/usr/src/app

A nyní spustíme příkaz:
docker-compose up --build

Tento příkaz nám podle Dockerfile a docker-compose.yml nám vytvoří a spustí Docker image, která přepisuje původní chování a tím je spuštění npm start na npm run dev. Současně s tím nám reaguje na změny stejně, jako v případě spuštění z lokálního stroje.

Nyní v browseru stačí přejít znovu na stránku http://localhost:8080, kde byste měli vidět bežící aplikaci. Současně s tím, pokud nyní změníte text v pages/index.js, uvidíte, že Vaše bežící aplikace na toto zareaguje a dojde k hot reloadu.

Výhodou Docker Compose je hlavně v tom, že nemusíte přepisovat Dockerfile pro lokální vývoj vs produkční běh. Docker Compose vám přepíše původní konfiguraci a tím pádem máte k dispozici jak produkční Docker image, tak image pro lokální vývoj.

Závěr

O Dockeru by se dalo napsat spoustu věcí. Jelikož se článek rozrostl, tak jsem nucen ho rozdělit na dvě části. Příště si ukážeme, jak náš Docker image uložit do Docker Hubu a současně, jak ho poté nasadit v Cloudu (Google Cloud, Azure).

I když Docker přidává další abstrakci Vaší aplikaci, tak věřte, že ona abstrakce je nakonec výhodná, protože Vás odstiňuje od nutnosti unifikovat běžící prostředí složitou konfigurací serverů a lokálních strojů.

středa 31. května 2017

Proč právě Typescript?

Pokud to někdo s vývojem v javascriptu myslí vážně, měl by hledat způsob, jak nejlépe napsat udržitelný kód.

Díky vlastnostem, které přinesly ES5 a ES6, máme již k dispozici jazyk, který se netváří tak nepřátelsky.

Nicméně, stále existuje jedna věc, kterou javascript nenabízí a která je u většího projektu dost zásadní. Tou vlastností je typovost.

Proč bychom měli chtít typy v javascriptu?


Odpověď je vcelku jednoduchá. Z důvodu udržitelnosti kódu.

Představte si situaci, že máte projekt, kde chcete provést refactoring či změnu v modelu aplikace. V případě, že váš projekt nemá typy, budete se muset spolehnout pouze na špičkově napsané testy, které vám prozradí, zda jste v kódu něco nerozbili :)

Pojďme si udělat malou ukázku.

Máme entitu uživatele, kterou zobrazujeme v tabulce. Zjednodušený kód by vypadal asi následovně:

const users = [
    {id: 1, firstName:  'Ales', lastName: 'Dostal', roles: ['admin']},
    {id: 2, firstName:  'Petr', lastName: 'Novotny', roles: ['operator']},
];

Nyní toto pole zobrazíme v tabulce:

users.map((row) => (
    <tr>
        <td>{row.firstName} {row.lastName}</td>
        <td>{row.roles.join(', ')}</td>
    </tr>
));

Tady je svět asi v pořádku, ale co nastane, když budete potřebovat provést změnu, která spočívá v tom, že atribut roles budete muset zahodit a říci, že uživatel může obsahovat pouze jednu roli? Atribut roles se přejmenuje na role a přijímat bude pouze jeden řetězec, ale nikoli pole.

const users = [
    {id: 1, firstName:  'Ales', lastName: 'Dostal', role: 'admin'},
    {id: 2, firstName:  'Petr', lastName: 'Novotny', role: 'operator'},
];

Co zbytek vašeho kódu?
Jen velice těžko budete dohledávat, zda objekt user obsahuje ty správné atributy, se kterými pracujete v metodě map, pro vypsání řádku tabulky. Javascript se bude tvářit, že je vše v pořádku a problém zjistíte až za běhu. A to skutečně nechce přeci nikdo.

Pojdmě náš kód obohatit o typovost pomocí Typescriptu. První věcí, kterou musíme udělat je, že si vytvoříme definici typu User.

interface User {
    readonly id: number;
    readonly firstName: string;
    readonly lastName: string;
    readonly roles: string[];
}

Nyní řekneme, že proměná users je typu pole User.

const users: User[] = [
    {id: 1, firstName: 'Ales', lastName: 'Dostal', roles: ['admin']},
    {id: 2, firstName: 'Petr', lastName: 'Novotny', roles: ['operator']},
];

A nyní, když budeme chtít změnit model, změníme definici.

interface User {
    readonly id: number;
    readonly firstName: string;
    readonly lastName: string;
    readonly role: string;
}

V té chvíli nám bude kompilátor Typescriptu vracet chybové hlášení, které nás upozorní, že máme špatně inicializovanou proměnou users a současně, že v metodě map předpokládáme, že existuje atribut roles, které je pole.

Teď si vemte tuto malou ukázku a vynásobte jí třeba 100x krát. Opravdu chcete ještě stavět projekt bez typů?

Co je tedy ten Typescript?


Typescript je jazyk, který byl představen v roce 2012 Microsoftem. V podstatě vychází z jednoduché myšlenky, která říká: "Pište klasicky v javascriptu, jen k němu přidejte typy".
I když Typescript má i další vlastnosti, které javascript nenabízí, tak jeho hlavní přínos je právě v oné přidané typovosti.

V praxi to vypadá tak, že píšete soubor, který si označíte jako typescript soubor (většinou pomocí přípony *.ts) a poté tento soubor zkompilujete kompilátorem Typescriptu. Výsledkem je javascriptový soubor, který je v dané ES specifikaci. O tom, do jaké specifikace chcete soubor kompilovat je na vás.

Více se o typescriptu můžete dozvědět z oficiálního webu.

Typescript není Java


Často se setkávám s tím, že lidé k Typescriptu přistupují jako k Jave. I když zde najdete spoustu společných vlastností, je dobré mít stále na paměti, že Typescript funguje jinak.
Jedním z hlavních rozdílů je to, že Typescript své typy porovnává na úrovni struktury.

Uveďme si příklad:

interface Cat {
    name: string;
}

interface Dog {
    name: string;
}

const cat: Cat = {name: 'Mourek'};
const dog: Dog = cat;

Proč tomu tak je?

Jde o to, že Typescript sice má typy, ale představte si, že jsou to stejně jen jakési flagy, které Vám mají pomáhat při psaní kódu. Poté, co se daný soubor zkompiluje do javascriptu, tak typy jsou odstraněny a pracuje se pouze s JSONem.

Další věcí je, že chyby, které Vám kompilátor Typescriptu bude hlásit můžete často ignorovat. Výsledný kód bude funkční, dokud…

Příkladem je také třeba klíčové slovo readonly, kterým pokud označíte atributy daného typu, tak tím říkáte, že je nelze přímo přepsat. Nicméně, pokud to v kódu ignorujete, tak výsledkem bude validní javascript, protože ten žádné klíčové slovo readonly nezná.
Proto budťe obezřetní, při psaní v Typescriptu. Pořád je třeba mít na paměti, že je to javascript, který si jen typuji.

Další možnosti, jak typovat javascript


Kromě Typescriptu zde existuje ještě jedna varianta, která ve své podstatě dělá to samé (i když jiným způsobem). Tou variantou je FlowType či označováno jen jako Flow. 

Flow je statická typová kontrola, kterou vytvořili lidé z facebooku. Na rozdíl od Typescriptu, je Flow méně invazivní a jedná se v podstatě pouze o "type check", kdežto v případě Typescriptu to je kompletní kompilace.

A proč tedy Typescript a ne Flow?


Tuto otázku jsem si pokládal dost často. Přeci jen, vždy máme touhy pokukovat po alternativách a hledat, zda někdo nemá ten "trávníček o něco zelenější". Já osobně jsem do Typescriptu šel ze dvou hlavních důvodů.

1. Typescript je tady déle a používá ho více knihoven
Tím, že byl první, tak z toho dodnes těží. Týká se to zejména knihoven, které když stáhnete z NPM, často se setkáte s problémem, že daná knihovna nemá definované typy. A pokud ano, je větší pravděpodobnost, že typy budou pro Typescript, nikoli pro Flow.

2. Angular 2
Ač jsem zastánce Reactu a Angular vnímám spíše jako ukázkovou cestu, kterou nejít, dá se zde mluvit o tom, že Typescript je nejvíce zpopularizován právě Angularem 2, který tento jazyk zvolil jako výchozí. Microsoft vytvoří jazyk a Google framework, který ho evangelizuje. Ironie, že? :)

Závěr


Už jste začali používat typy v javascriptu? :)

pondělí 29. srpna 2016

React JS: Jak začít?

V předchozím příspěvku jsem se věnoval drobnému porovnání React a Angular 2. Nyní se pojďme podívat na to, jak začít....

Mnoho nových termínů a technologií

Před tím, než se pustíte do vývoje webové aplikace pomocí Reactu, dostane se Vám do ruky nepřeberné množství technologíí, které s tímto vývojem souvisí.
Jak už jsem zmiňoval, tak i přesto, že Angular 2 nabízí možnost "all in one", tak ani tam se nevyhnete tomu, že se budete muset naučit pracovat s několika novými "pojmy".
Myslím si, že právě to, že postavit funkční dev stack je vcelku alchymie, dochází k tomu, že mnoho lidí skončí dřív, než vůbec začne.
K tomu, jak správně začít se dozvíte z tohoto článku.

React DEV stack

Tento DEV stack vychází z mého vlastního návrhu. Inspiraci jsem čerpal jak z diskuzních fór typu stackoverflow.com, tak i z různých blogů na toto téma. Pojďme to tedy vzít postupně....

https://www.npmjs.com/

I když je React možné provozovat tak, že do index.html vložíte odkaz na js soubory Reactu, tak počítejte s tím, že tento způsob je dobrý maximálně na prototypování, tedy na vyzkoušení si, jak vlastně psát v Reactu komponenty.
V budoucnu se dostanete do fáze, kdy budete potřebovat řešit i jiné knihovny, verzování, spouštění skriptů, apod. K tomuto účelu slouží právě NPM, což není nic jiného, než package manager pro javascript.
Pomocí NPM si nalinkujete vše, co Vaše aplikace bude potřebovat. Ať už je to bootstrap, jQuery či knihovny typu Redux, apod.
NPM se definuje pomocí souboru package.json. V něm definujete jak dané knihovny, tak i samotné skripty, které chcete spouštět. Poté již stačí jen v daném adresáři napsat: "npm install" a všechny Vaše knihovny se automaticky stáhnou a nainstalují do adresáře node_modules.
Spouštění skriptů se provádí pomocí "npm run xxx". Kde za xxx dosadíte název z package.json.

Webpack

Bohužel pouze s NPM si nevystačíte. Sice už víte jak správně přidávat nové knihovny, ale stále před Vámi bude problém ohledně toho, jak správně aplikaci sestavit, jak spustit debug, jak vytvořit produkční build, apod. K tomuto účelu slouží právě Webpack. 
Existují i varianty typu Gulp či Grunt, nicméně věřte, že právě Webpack všechny tyto alternativy překonává.
Důvodem proč, je to, že pokud budete ignorovat Webpack a půjdete cestou třeba Gulpu, Vaše aplikace bude obsahovat šílený Gulp skript, kterým budete ovládat jednotlivé potřeby Vaší aplikace.
Webpack na to jde jinak. Pomocí modulů.
Napadá mě jedna hezká synergie: Gulp = Ant, Webpack = Maven :)

Typescript

Pokud čekáte, že se javascriptové aplikace píší v čistém javascriptu, musím Vás zklamat. Téměř nikdo to nedělá. Tedy alespoň ne ti, kteří to myslí skutečně vážně :)
Asi by se našlo hodně lidí, kteří by předchozí větu zpochybnili a jistě by měli pravdu. Mnoho lidí píše v javascriptu, ale ne v tom, který je aktuálně podporován většinou prohlížečů. Zkusím to trochu více rozvést....
Javascript spadá do specifikace ECMA Scriptu. ECMA Script není javascript a javascript není ECMAScript. ECMAScript je specifikace :)
V současné době je ve vývoji verze 7. I když je verze 6 už více jak rok stará, tak bohužel většina webových prohlížečů stále na 100% nepodporuje všechny její vlastnosti.
Jelikož rádi zkoušíme nové věci a rádi bychom využívali nové možnosti, které daný jazyk nabízí (a v případe specifikace ECMA Scriptu, to jsou skutečně zajímavé vlastnosti), tak hledáme způsob, jak je využít již teď.
Proto mnoho vývojářů začalo používat transformaci, kde aplikaci napíší ve specifikaci ECMA 6 a převedou ji do verze ECMA 5, se kterým si většina webových prohlížečů již poradí.
K tomuto účelu výborně slouží Babel. 
Touto cestou se vydal také React a většinu aplikací, které naleznete na github.com, jsou napsány právě pomocí Babelu.
Bohužel stále zde existuje jeden velký neduh a to je typovost. Psaní v ECMA 6 je sice výrazně lepší varianta, nicméně není to ideální volba.
Microsoft přišel s vlastní specifikací jazyka, který se jmenuje Typescript. Typescript je například výchozím jazykem pro Angular 2. Důvod, proč Google zvolil technologii Microsoftu je to, že i když je Typescript vlastní jazyk, je plně kompatibilní s ECMA specifikací.
Jinými slovy, to znamená, že v typescriptu můžete psát jako v javascriptu a on bude stále validní.
Výhoda Typescriptu je zejména v tom, že jde za hranice ECMA Scriptu 6. Nabízí totiž typovost, která Vám bude zaručovat lepší konzistenci celého projektu.
Jedinou nevýhodou, která je s Reactem spojena, je to, že React na začátku zvolil Babel a proto je většina ukázek práve s ECMA 6 a nikoli v Typescriptu. Nicméně není třeba se bát. Psát pomocí Typescriptu v Reactu je pohodlné a osobně jsem nenarazil na problém, který by neměl řešení. Pro představu, jak psát pomocí v Reactu Typescriptu je zde: React a Typescript. 
Doporučení na závěr: NIKDY NEPIŠTĚ ČISTÝM JAVASCRIPTEM. Pokud Vám Typescript z nějakého důvodu nevyhovuje, zvolte alespoň transformaci pomocí Babelu. Nicméně Typescript je nejlepší volba, kterou můžete nyní zvolit.

Redux

O reduxu jsem psal v minulém přispěvku. Hned po té, co ovládnete React, implementujte Redux. Důvody, proč zvolit Redux je jednoduchá. Budete mít stav své aplikace pod kontrolou.

React Router

Samotnými komponenty Reactu si v aplikaci skutečně nevystačíte. Pokud hledáte, jak správně routovat, existuje jasná volba. 
Možná Vás napadne myšlenka, proč není React Router součástí Reactu. Důvodem je to, že React Router slouží pro webové aplikace a samotný React neslouží jen pro psaní webů. Existuje zde totiž možnost, psát v Reactu i mobilní aplikace. K tomuto účelu slouží React Native. Proto je React Router jako vlastní knihovna a není jeho součástí. React Native je zajímavá alternativa, jak psát mobilní aplikace a v budoucnu o této technologii jistě něco napíši.


Redux Thunk

Pokud použijete Redux, tak se dostanete k jedné zásadní otázce. Tou je, jak se poprat s asynchronním zpracováním. Redux Thunk nedelá nic jiného, než to, že Vám v rámci akce umožňuje získat dispatch instanci, díky které, můžete vyvolat akci i uvnitř asynchronní metody.
To je na Reduxu a Reactu skvělé. Napadlo Vás někdy, že například Facebook umožňuje ukázat návrh bloku, do kterého se vykreslí komentáře, aniž by dané komentáře byly ze serveru již načteny?
Funguje to tak, že například řeknete, že chcete ze serveru stáhnout další položky. Reduceru pošlete informaci o změně a díky tomu se UI komponenta může začít měnit. Nicméně, vedle toho se ptáte serveru a čekáte na skutečnou změnu, která až Vám přijde, tak jí přepíšete v reduxu, pomocí stejného reduceru :)

Fetch

Poslední věcí, o které zde napíší je whatwg-fetch. Jak už jsem minule zmiňoval, tak React neobsahuje knihovnu na volání Vašeho REST (GraphQL) server API. K tomuto účelu můžete využít několik knihoven. Jedna je samozřejmě i přímo v jQuery. Osobně jsem na doporučení zvolil Fetch, což je knihovna doporučována snad všemi.
Fetch se snaží držet standardů a navíc její použití je velmi jednoduché.
V budoucnu se snad dočkáme i toho, že samotný ajax call půjde udělat přímo díky podpoře webových prohlížečů. Firefox a Chrome již dnes totiž podporují možnost window.fetch.

Závěr

Toto byl výčet těch nejdůležitějších technologií a knihoven, které při tvorbě webové aplikace Reactem lze využít. Osobně mám pár dalších technologií, které jsou již dost okrajové a mohou se měnit na základě požadavků na Vaší aplikaci. Tento výčet je ovšem základ, který bych použil vždy, když bych se dostal k vývoji webové aplikace Reactem.
Ještě bych rád zmínil jedno doporučení. Pokud začnete hledat knihovny, které by Vám pomohly při tvorbě aplikace, byl bych obezřetný, abyste svůj projekt příliš nezahltili knihovnami třetích stran, které jsou často tvořeny jednou osobou. Na každý problém totiž v NPM naleznete knihovnu, která by Vám mohla pomoci. Bohužel je problém v tom, že jich je příliš mnoho a některé mají jepičí život. Buďte skutečně opatrní a spíše se koukejte po tom, zda je daná knihovna skutečně využívána a například díky githubu bych si zkontroloval, zda je aktuální a někdo na ní pracuje.

Když programátor založí a řídí firmu

Jako malý jsem chtěl být popelářem. Ani ne tak proto, že bych měl nějaký zvláštní vztah k odpadkům, ale hrozně se mi líbilo, jak...