úterý 20. února 2018

Nová verze Next.js 5 a Typescript


Před pár dny vyšla nová verze nejpoužívanejšího stacku pro React: Next.js 5.0. Seznam změn lze nalézt na oficiálním blogu. Jednou z klíčových vlastností je i podpora pluginů a to zejména pluginu @zeit/next-typescript.

Samotný example od Next.js bohužel neposkytuje ukázku, jak zprovoznit custom server s Typescriptem. Pokud Vás zajímá, tak jak provozovat next-typescript plugin s custom serverem, tak čtěte dál :)

Custom server a Typescript

V případě, že používáte custom server, je třeba samotnou konfiguraci obohatit o několik dalších kroků.

Začněme nejdříve přípravou skriptů v package.json:
  "scripts": {
    "prebuild": "rimraf dist/ && rimraf .next/",
    "build": "next build && tsc --module commonjs",
    "start": "NODE_ENV=production node dist/index.js",
    "dev": "nodemon server/index.ts"
  }

Dalším krokem je úprava tsconfig.json:
{
  "compileOnSave": false,
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "jsx": "preserve",
    "allowJs": true,
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "removeComments": false,
    "preserveConstEnums": true,
    "sourceMap": true,
    "skipLibCheck": true,
    "outDir": "dist",
    "baseUrl": ".",
    "typeRoots": [
      "./node_modules/@types"
    ],
    "lib": [
      "dom",
      "es2015",
      "es2016"
    ]
  },
  "include": [
    "server/**/*.ts"
  ]
}

Soubor nodemon.json:
{
  "watch": [
    "server/**/*.ts"
  ],
  "execMap": {
    "ts": "ts-node --compilerOptions '{\"module\":\"commonjs\"}'"
  }
}

Soubor next.config.js (v ukázce je i custom konfigurace webpacku):
require('dotenv').config();
const withTypescript = require('@zeit/next-typescript');
const webpack = require('webpack');

module.exports = withTypescript({
    webpack(config) {
        config.plugins = [
            ...config.plugins || [],
            new webpack.DefinePlugin({
                'process.env.BACKEND_ENDPOINT': JSON.stringify(process.env.BACKEND_ENDPOINT),
            }),
        ];
        return config;
    },
});

Aby byl projekt validní, je třeba dodržet následujcící adresářovou strukturu:

  • server/index.ts - custom node.js server
  • pages/*.tsx - jednotlivé Next.js / React stránky
  • .next/ - build samotného Next.js (viz npm run build)
  • dist/index.js - zkompilovaný custom server (viz npm run build)

Závěr


Next.js a Typescript je nyní ve skvělé symbióze. Server side renderingu zdar! :)

čtvrtek 1. února 2018

Co je špatně na interních knihovnách a frameworcích?

Než se pustím do rozboru, co je špatně na interních knihovnách a frameworcích, chtěl bych předat jednu radu byznysu a vývojářům.

Rada pro byznys

"Pokud Vám vývoj řekne, že na Váš problém mají připravený vlastní interní framework, tak utečte."

Rada pro vývojáře

"Pokud Vám při pohovoru řeknou, že používají vlastní interní framework, tak utečte."


Téměř každý vývojář se někdy dostal do stavu, kdy si řekl, že by bylo vhodné, aby si napsal vlastní podpůrné knihovny pro potřeby, které zrovna řeší.
Tahle cesta je ovšem často dlážděna takovými překážkami, že je velice málo projektů, které nakonec uspějí. Je to stejné, jako když třeba založíte firmu. Jaká je pravděpodobnost, že přežijete? Že ustojíte první rok? První překážku, první úspěch, který vás může nakonec natolik pohltit, že vás zničí?

Rád se vždy vracím do minulosti a nebude tomu jinak ani teď.

Pamatuji si, když jsem začal s programováním jako hlavní profesí. V té době jsem pracoval jako PHP vývojář. Abyste byli v obraze, tak tenkrát bylo PHP ve verzi 4. Kromě toho, že ten jazyk pořádně neuměl typy a měl divně navržené argumenty metod, tak hlavně trpěl vysokou absencí podpůrných knihoven a frameworků.
Tenkrát se často přistupovalo k řešení, které je sexy pro každého vývojáře. Napsat si vlastní framework! Kdo to tenkrát nedělal, tak buď byl dostatečně chytrý, že věděl, že to není dobrý nápad a nebo nepsal v PHP nic velkého.

Já jsem tenkrát pracoval na informačním systému, který byl složen hlavně z reportingu. Jako každý správný reporting i ten náš obsahoval "sofistikovaný datagrid". Cesta byla jasná. Napsat si vlastní knihovnu na datagrid.
Jenže tím tato cesta nekončí. Kde mám podporu pro psaní dotazů do databáze? Kde mám podporu pro routing? Kde mám podporu pro customizaci datagridu? No, zkráceně řečeno, skončil jsem s nečím, co jsem si dovolil nazvat "framework".

I když to byla zajímavá práce a částečně nakonec ušetřila vývoj, tak nakonec skončila v propadlišti dějin. Tím důvodem nebylo nic jiného, než to, že jsem daný framework nikdy nedal jako opensource. Kdybych to tenkrát udělal, možná by se to setkalo úspěchem, možná ne, ale každopádně to byla chyba.

Jako ponaučení jsem si nakonec odnesl jednu důležitou věc:
"Pokud svou knihovnu nedám k dispozici jako opensource, vždy skončí v propadlišti dějin."

Ponaučen tím, že psát si vlastní framework je jedna z nejtěžších disciplín, jsem si řekl, že touto cestou již nikdy nepůjdu. Jak já se mýlil...

V době, kdy jsem již několik let byl v pozici Java programátora, tak jsem se často setkával s tím, že na každý problém existuje nějaké řešení. V tom je Java dodnes skvělá. Na server straně často najdete dostatek knihoven, které vám pomůžou řešit váš problém. Jenže bylo několik oblastí, kde J2EE stále pokulhávalo.

Jednou z oblastí bylo, že v případě, že jste použili prvotní verze Glassfish a EJB, tak se vám težko psali integrační testy jinak, než že jste museli celou aplikaci nasadit na server a tam testy spustit. Tedy z testů se stala spíše noční můra.
Jenže to bych nebyl já, abych si zase nehledal svou cestu. Tou cestou bylo řešení v podobě vlastního kontejneru.
O co šlo? Když jsem se zamyslel nad tím, co má aplikace na serveru dělá a jak funguje, řekl jsem si, že vlastně to není nic složitého. Přečte anotaci @EJB (v té době skvělá novinka) a kontejner zařizuje dependency injection. K tomu bylo pár dalších vlastností jako je scope, transakce či JNDI.
A jelikož Glassfish neměl embedded režim, tak jsem si řekl, že si to napíšu.
Nakonec jsem skončil s knihovnou, která pomocí Java reflexe přečetla dané anotace. Jinak řečeno, napsal jsem si vlastní DI kontejner :)
Řešení bylo efektivní. Testy startovaly rychle a já mohl nějaké ty testy napsat.
Jenže opět jsem selhal v tom, že jsem si dané řešení nechal jen pro sebe a navíc jsem se pořádně nesnažil použít jiné alternativy.
Po nějaké době jsem nakonec zjistil, že Glassfish vydal embedded variantu a celé mé řešení vlastně bylo k ničemu.

Jako ponaučení jsem si nakonec odnesl následující:
"Než začnu psát vlastní řešení, pořádně se podívám, zda neexistuje jiná alternativa. A i za cenu drobných ztrát to vždy bude lepší varianta."

V následujících letech jsem od takto "kreativních" činností začal upouštět. Jednak to bylo tím, že jsem spíše putoval po projektech, kde jsem vždy byl pouze dočasně a jednak také proto, že jsem byl přesvědčen, že na to, aby člověk vytvořil skutečně dobrou knihovnu, nestačí jí jen napsat, ale také nekonečně podporovat.

S čím jsem se ovšem setkal, byla naprostá zrůdnost v podobě šílených interních legacy knihoven a frameworků. Vždy jsem si představoval, jak něco takového asi vzniklo. Mám pocit, že často stejně jako v mém případě. Je prostě "sexy" si napsat vlastní framework. Jsem chytrejší než zbytek světa, tak si napíšu vlastní knihovnu, která bude dokonalá, obsáhne celý problém, pohltí celý svět a bude jednou stát na piedestalu: "Nejlepší framework světa".

Jenže, co se ve výsledku stane? Takováto interní knihovnička se časem stane největší brzdou celého vývoje. Původní autor už dávno odešel, dokumentace je neaktuální a bugy se řeší workaroundy, místo aby došlo k nápravě.

Nedílnou součástí takovéhle knihovny či frameworku je šílená enterprise struktura, kde jeden objekt má cca tisíc abstraktních předků a to právě kvůli tomu, že je to prostě "cool".

Použití takovéhle knihovny pak často vyžaduje mít IQ alespoň 350 a 10 letou praxi.

Pokud jsem psal, že tvorba knihoven a frameworků je jedna z nejsložitějších disciplín v programování, tak s tím souvisí i určitá seniorita v oboru. Prvním znakem je třeba to, že na místo dědičnosti je vždy lepší upřednostňovat kompozici. Důvodem je totiž fakt, že dědičnost v OOP je předpovídání budoucnosti. To už je menší šarlatánství čtení budoucnosti z ruky.

Jako ponaučení jsem si nakonec odnesl následující:
"Vytvořit univerzální řešení je iluze. Ze stříbrné kulky se nakonec stává zlomená lopata."

Další zajimavou disciplínou je něco, co jsem si interně nazval jako "obalování". Obalování je činnost, kdy vlastně neděláte nic jiného, než že stalé dokola přepisujete API nějaké knihovny do vlastních metod.
Důvod, proč někdo něco takového dělá je často způsobeno tím, že je přesvědčen, že jeho obalující API je lepší než to, které nabízí knihovna. Jenže to není tak úplně pravda. Je mnohem větší pravděpodobnost, že ono "obalování" vývojáři dělají z toho důvodu, že si pak lépe pamatují co ono API dělá. Někdy je totiž časově náročné se dané API učit.

A opět jedno ponaučení:
"Místo obalování API svým vlastním je lepší věnovat čas existujícímu API a to využít na max. Je totiž velká pravděpodobnost, že píšete kód, který je ve výsledku úplně k ničemu."

Když jsem přemýšlel, jak z toho nakonec ven, tak jsem si uvědomil, že to nelze. Nelze to už jen z toho důvodu, že programátory často pohání ona touha po tvorbě dokonalé knihovny. Myslet si, že v budoucnu bude situace jiná je dost lichá. Důvodem není nic jiného, než to, že jsme jen lidé a ti jsou často odsouzeni k opakovaným chybám.

Abych se v budoucnu vyhnul tomu, že bych někdy zklouznul k opětovné tvorbě "vlastního frameworku", tak jsem si vytvořil několik pravidel, které mě vždy dost jasně zastaví:

  1. Pokud vytvořím univerzální knihovnu či framework, vždy musí být opensource.
  2. Musím vytvořit srozumitelnou dokumentaci
  3. Musím knihovnu stále udržovat a je velká pravděpodobnost, že na to budu sám
  4. Kód musí obsahovat testy
  5. Testy musí být udržované
  6. Pokud má knihovna nezíská další konzumenty, je odsouzena k zániku
  7. Hlášené chyby musím opravovat ASAP
  8. Kód dané knihovny musí mít vysokou kvalitu
  9. Musím knihovnu správně verzovat a umět opravovat chyby i ve starších verzích
  10. Napsat vlastní knihovnu či framework je extrémně pracné a nakonec přináší spoustu problémů

Závěr

"Chceš napsat vlastní knihovnu či framework? OK. Vytvoř kód, dej ho na GitHub a až bude mít alespoň 1000 stars, tak se vrať a řekni, že máš knihovnu či framework."



React a hrátky s TypeScriptem

V minulosti jsem se již několikrát zmiňoval, že používat JavaScript bez statických typů, je stejné jako jezdit na kole poslepu. Nemusí se...