SlideShare a Scribd company logo
1 of 49
Download to read offline
from Madness to Reason
@romanschejbal
from React to ReasonReact
SYNTAX & TOOLCHAIN FOR OCAML
BATTLE-TESTED PROGRAMMING LANGUAGE
Bucklescript
https://github.com/facebook/reason/blob/master/src/README.md
OCaml?
Why should I care? 🤔
Effective & Functional
✔
But Still Practical
Statically Type Checked
✔
Compiler Errors
We've found a bug for you!
/workspace/reason/src/Student.re 20:30
19 │ let age = 2;
20 │ let greeting = greet(Student(1));
21 │
22 │ Js.log(greeting);
This has type:
int
But somewhere wanted:
string
You can convert a int to a string with string_of_int.
Good Support For
Immutable Programming
✔
Automatic Type Inference
(less type definitions)
Autocurrying
the “Madness”
@romanschejbal
let name = "Reason";
let age = 2;
let greet = () => "Hello World!";
Language Basics
Algebraic data types
type name = option(string); /* None | Some(“Reason”) */
type state = { items: array(string), length: number };
type schoolPerson =
| Teacher
| Director
| Student(string);
type schoolPerson = Teacher | Director | Student(string);
let greet = stranger =>
switch (stranger) {
| Teacher => "Hey professor!"
| Director => "Hello director."
| Student("Richard") => "Still here Ricky?"
| Student(anyOtherName) => "Hey, " ++ anyOtherName ++ "."
};
greet(Teacher); /* Hey professor! */
greet(Student("OCaml")); /* Hey, OCaml. */
Variants & Pattern Matching
Pattern Matching Exhaustiveness
Warning number 8
/workspace/reason/src/Student.re 7:3-12:3
5 │
6 │ let greet = stranger =>
7 │ switch (stranger) {
8 │ | Teacher => "Hey professor!"
. │ ...
11 │ /* | Student(anyOtherName) => "Hey " ++ anyOtherName ++ "." */
12 │ };
13 │
14 │ print_endline(greet(Teacher));
You forgot to handle a possible value here, for example:
Student ""
type userT = option(string);
let userOne = Some("X");
let userTwo = None;
let printPlayerName = player =>
switch (player) {
| Some(name) => "Logged in as " ++ name
| None => "Not logged in"
};
Option type
Why Reason then? 🤔
“We want people to be
able to use powerful, well-
typed languages at work,
not just in their free time.”
- Jordan Walke
https://jaredforsyth.com/type-safe-react-native/
How Do I Start 🧐
CRA & Redux
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | |- store.js
| |- App.js
| |- index.js
| package.json
| bsconfig.json
| yarn.lock
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | |- store.js
| |- App.js
| |- index.js
| package.json
| bsconfig.json
| yarn.lock
yarn add bs-platform reason-react
bsconfig.json
{
"name": "my-project",
"namespace": true,
"sources": [
{
"dir": "src",
"subdirs": true
}
],
"package-specs": {
"module": "es6-global",
"in-source": true
},
"suffix": ".bs.js",
"bs-dependencies": ["reason-react"],
"reason": {
"react-jsx": 2
}
}
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | |- store.js
| |- App.js
| |- index.js
| package.json
| bsconfig.json
| yarn.lock
package.json
{
"name": "from-react-to-reason",
"version": "0.1.0",
"private": true,
"dependencies": {
"bs-platform": "^3.0.0",
"flow-bin": "^0.72.0",
"react": "^16.3.2",
"react-dom": "^16.3.2",
"react-redux": "^5.0.7",
"react-scripts": "1.1.4",
"reason-react": "^0.4.1",
"redux": "^4.0.0",
"redux-thunk": "^2.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"bsb": "bsb -make-world -w"
}
}
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | |- store.js
| |- App.js
| |- index.js
| package.json
| bsconfig.json
| yarn.lock
"bsb": "bsb -make-world -w"
src/Types.re
[@bs.deriving jsConverter]
type flightInfo = {
airline: string,
price: int,
duration: float,
};
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
Record Type
src/Types.bs.js
// Generated by BUCKLESCRIPT VERSION 3.0.0, PLEASE EDIT WITH CARE
function flightInfoToJs(param) {
return {
airline: param[ /* airline */0],
price: param[ /* price */1],
duration: param[ /* duration */2]
};
}
function flightInfoFromJs(param) {
return /* record */[
/* airline */param.airline,
/* price */param.price,
/* duration */param.duration
];
}
export {
flightInfoToJs ,
flightInfoFromJs ,
}
/* No side effect */
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/reducer/index.js
import {
type actionT,
REQUEST_FLIGHTS,
RECEIVE_FLIGHTS,
FAILURE_FLIGHTS,
} from ' ../action';
const initialState = {
loading: false,
flights: [],
error: null,
};
export default (state = initialState, action) => {
switch (action.type) {
case REQUEST_FLIGHTS:
return { ...state, loading: true };
case RECEIVE_FLIGHTS:
return { ...state, loading: false, flights: action.payload.flights };
case FAILURE_FLIGHTS:
return { ...state, error: action.payload.error };
default:
return state;
}
};
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/reducer/Reducer.re
type flightsData = array(Types.flightInfo);
[@bs.deriving jsConverter]
type state = {
loading: bool,
flights: flightsData,
error: option(Js.Exn.t)
};
let initialState = {
loading: false,
flights: [ ||],
error: None
};
let default = (state, action) =>
switch (action ##_type) {
| "REQUEST_FLIGHTS" => { ...state, loading: true}
| "RECEIVE_FLIGHTS" => {
...state,
flights: Array.map(Types.flightInfoFromJs, action ##payload ##flights),
loading: false,
}
| "FAILURE_FLIGHTS" => { ...state, error: action ##payload ##error}
};
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/reducer/Reducer.re
Warning number 8
/Users/roman/workspace/from-react-to-reason/src/state/reducer/Reducer.re 21:3-30:3
19 │
20 │ let default = (state, action) =>
21 │ switch (action##_type) {
22 │ | "REQUEST_FLIGHTS" => {...state, loading: true}
. │ ...
29 │ | “FAILURE_FLIGHTS" => {...state, error: action##payload##error}
30 │ };
31 │
32 │ /* let default = (state, action) => {
You forgot to handle a possible value here, for example:
""
src/state/reducer/Reducer.re
type flightsData = array(Types.flightInfo);
type state = {
loading: bool,
flights: flightsData,
error: option(Js.Exn.t)
};
let initialState = {
loading: false,
flights: [ ||],
error: None
};
let default = (state, action) =>
switch (action ##_type) {
| "REQUEST_FLIGHTS" => { ...state, loading: true}
| "RECEIVE_FLIGHTS" => {
...state,
flights: Array.map(Types.flightInfoFromJs, action ##payload ##flights),
loading: false,
}
| "FAILURE_FLIGHTS" => { ...state, error: action ##payload ##error}
| _ => state
};
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
| _ => state
src/state/action/index.js
export const REQUEST_FLIGHTS = 'REQUEST_FLIGHTS';
export const RECEIVE_FLIGHTS = 'RECEIVE_FLIGHTS';
export const FAILURE_FLIGHTS = 'FAILURE_FLIGHTS';
export const fetchFlights = (where, when) => (
dispatch
) => {
dispatch(requestFlights());
setTimeout(
() =>
dispatch(
receiveFlights([
{ airline: 'British Airways', price: 390, duration: 3.5 },
{ airline: 'KLM', price: 340, duration: 2.2 }
])
),
3000
);
};
const requestFlights = () => ({
type: REQUEST_FLIGHTS
});
const receiveFlights = (flights: Array<Object>) => ({
type: RECEIVE_FLIGHTS,
payload: { flights }
});
const failureFlights = (error: Error) => ({
type: FAILURE_FLIGHTS,
payload: { error }
});
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/action/Actions.re
let fetchFlights = (from, where, when) =>
(. dispatch) => {
dispatch(requestFlights(from, where, when));
Js.Global.setTimeout(
() =>
dispatch(
receiveFlights( [|
{airline: "British Airways", price: 390, duration: 3.5},
{airline: "KLM", price: 340, duration: 2.2},
|]),
),
3000,
);
};
let requestFlights = (from, where, when) => {
"type": "REQUEST_FLIGHTS",
"payload": {
"from": from,
"where": where,
"when": when,
},
};
let receiveFlights = flights => {
"type": "RECEIVE_FLIGHTS",
"payload": {
"flights": flights,
},
};
...
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | | |- Actions.re
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducer/Reducer.bs';
const initialState = undefined;
export default () =>
createStore(
rootReducer,
applyMiddleware(thunk),
initialState
);
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | | |- Actions.re
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
What have we gained?
1. Can’t mess up our state shape
Can we get more?
src/state/action/Actions.re
let fetchFlights = (from, where, when) =>
(. dispatch) => {
dispatch(requestFlights(from, where, when));
Js.Global.setTimeout(
() =>
dispatch(
receiveFlights( [|
{airline: "British Airways", price: 390, duration: 3.5},
{airline: "KLM", price: 340, duration: 2.2},
|]),
),
3000,
);
};
let requestFlights = (from, where, when) => {
"type": "REQUEST_FLIGHTS",
"payload": {
"from": from,
"where": where,
"when": when,
},
};
let receiveFlights = flights => {
"type": "RECEIVE_FLIGHTS",
"payload": {
"flights": flights,
},
};
let failureFlights = error => {
"type": "FAILURE_FLIGHTS",
"payload": {
"error": error,
},
};
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | | |- Actions.re
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/action/Actions.re
type from = string;
type where = string;
type when = string;
[@bs.deriving accessors]
type action =
| RequestFlights(from, where, when)
| ReceiveFlights(array(Types.flightInfo))
| FailureFlights(Js.Exn.t);
let fetchFlights = (from, where, when) =>
(. dispatch) => {
dispatch(RequestFlights(from, where, when));
Js.Global.setTimeout(
() =>
dispatch(
ReceiveFlights( [|
{airline: "British Airways", price: 390, duration: 3.5},
{airline: "KLM", price: 340, duration: 2.2},
|]),
),
3000,
);
};
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | | |- Actions.re
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/action/Reducer.re
type flightsData = array(Types.flightInfo);
[@bs.deriving jsConverter]
type state = {
loading: bool,
flights: flightsData,
error: option(Js.Exn.t),
};
let initialState = {
loading: false,
flights: [ ||],
error: None,
};
let default = (state, action) => {
Actions.(
switch (action) {
| RequestFlights(_, _, _) => { ...state, loading: true}
| ReceiveFlights(flights) => { ...state, flights}
| FailureFlights(error) => { ...state, error: Some(error)}
}
)
};
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | | |- Actions.re
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/state/store.js
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducer/Reducer.bs';
const fromReasonToJs = store => next => action => {
if (action.tag !== undefined) {
// reason action
const { tag } = action;
action = {
type: `REASON_ACTION_${tag}`,
tag,
reasonAction: action
};
}
next(action);
};
const reasonReducer = reducer => (state, action) => {
if (action.reasonAction) return reducer(state, action.reasonAction);
return reducer(state, { ...action, tag: -1 });
};
const initialState = undefined;
export default () =>
createStore(
reasonReducer(rootReducer),
applyMiddleware(thunk, fromReasonToJs),
initialState
);
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| |- state/
| | |- action/
| | | |- index.js
| | | |- Actions.re
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
src/components/FlightList.re
open ReasonReact;
let component = statelessComponent("FlightsList");
let make = (~data, _children) => {
...component,
render: _self =>
<div>
(
Array.map(
flightInfo =>
<div>
<h2> (string(flightInfo.airline)) </h2>
<p>
(string("Price: $" ++ string_of_int(flightInfo.price)))
(
string(
" | Duration: "
++ string_of_float(flightInfo.duration)
++ "hours",
)
)
</p>
</div>,
data,
)
|> array
)
</div>,
};
let default =
wrapReasonForJs(~component, jsProps =>
make(~data=jsProps ##data, jsProps ##children)
);
flight-search/
|- public/
|- node_modules/
|- public/
|- src/
| |- components/
| | |- flight-list.js
| | | |- FlightList.js
| |- state/
| | |- action/
| | | |- index.js
| | | |- Actions.re
| | |- reducer/
| | | |- index.js
| | | |- Reducer.re
| | |- store.js
| |- App.js
| |- index.js
| |- Types.re
| package.json
| bsconfig.json
| yarn.lock
What have we gained?
1. Can’t mess up our state shape
2. Can’t forget to handle actions
3. Can’t forget to handle edge cases
Not covered…
• Rendering a JS component from a Reason component
• Using Variants for async stuff i.e.
[@bs.module]
external myJSComponent : ReasonReact.reactClass = “./my-js-component“;
let make = (~name: string, ~age: option(int)=?, children) =>
ReasonReact.wrapJsForReason(
~reactClass=myJSComponent,
~props={"name": name, "age": Js.Nullable.fromOption(age)},
children,
);
type async('a) =
| Idle
| Loading
| Success('a)
| Error(Js.Exn.t);
type action =
| Tick(unit)
| Flights(Types.(async(array(flightInfo))));
http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html
THANKS!
@romanschejbal
github.com/romanschejbal/from-react-to-reason

More Related Content

What's hot

Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram VaswaniCreating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswanivvaswani
 
AngularJS with Slim PHP Micro Framework
AngularJS with Slim PHP Micro FrameworkAngularJS with Slim PHP Micro Framework
AngularJS with Slim PHP Micro FrameworkBackand Cohen
 
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)James Titcumb
 
Keep It Simple Security (Symfony cafe 28-01-2016)
Keep It Simple Security (Symfony cafe 28-01-2016)Keep It Simple Security (Symfony cafe 28-01-2016)
Keep It Simple Security (Symfony cafe 28-01-2016)Oleg Zinchenko
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkJeremy Kendall
 
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...Caldera Labs
 
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложения
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложенияCodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложения
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложенияCodeFest
 
Getting into ember.js
Getting into ember.jsGetting into ember.js
Getting into ember.jsreybango
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersCaldera Labs
 
Workshop 24: React Native Introduction
Workshop 24: React Native IntroductionWorkshop 24: React Native Introduction
Workshop 24: React Native IntroductionVisual Engineering
 
How to driver your webservices with ansible
How to driver your webservices with ansibleHow to driver your webservices with ansible
How to driver your webservices with ansibleGonéri Le Bouder
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportBen Scofield
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesjerryorr
 

What's hot (18)

Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram VaswaniCreating REST Applications with the Slim Micro-Framework by Vikram Vaswani
Creating REST Applications with the Slim Micro-Framework by Vikram Vaswani
 
AngularJS with Slim PHP Micro Framework
AngularJS with Slim PHP Micro FrameworkAngularJS with Slim PHP Micro Framework
AngularJS with Slim PHP Micro Framework
 
DrupalCon jQuery
DrupalCon jQueryDrupalCon jQuery
DrupalCon jQuery
 
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)Crafting Quality PHP Applications (Bucharest Tech Week 2017)
Crafting Quality PHP Applications (Bucharest Tech Week 2017)
 
Workshop 6: Designer tools
Workshop 6: Designer toolsWorkshop 6: Designer tools
Workshop 6: Designer tools
 
Oro meetup #4
Oro meetup #4Oro meetup #4
Oro meetup #4
 
Keep It Simple Security (Symfony cafe 28-01-2016)
Keep It Simple Security (Symfony cafe 28-01-2016)Keep It Simple Security (Symfony cafe 28-01-2016)
Keep It Simple Security (Symfony cafe 28-01-2016)
 
Keeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro frameworkKeeping it small: Getting to know the Slim micro framework
Keeping it small: Getting to know the Slim micro framework
 
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
Single Page Web Apps As WordPress Admin Interfaces Using AngularJS & The Word...
 
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложения
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложенияCodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложения
CodeFest 2014. Пухальский И. — Отзывчивые кроссплатформенные веб-приложения
 
Getting into ember.js
Getting into ember.jsGetting into ember.js
Getting into ember.js
 
Introduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress DevelopersIntroduction to AngularJS For WordPress Developers
Introduction to AngularJS For WordPress Developers
 
Workshop 24: React Native Introduction
Workshop 24: React Native IntroductionWorkshop 24: React Native Introduction
Workshop 24: React Native Introduction
 
GHC
GHCGHC
GHC
 
Silex Cheat Sheet
Silex Cheat SheetSilex Cheat Sheet
Silex Cheat Sheet
 
How to driver your webservices with ansible
How to driver your webservices with ansibleHow to driver your webservices with ansible
How to driver your webservices with ansible
 
And the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack SupportAnd the Greatest of These Is ... Rack Support
And the Greatest of These Is ... Rack Support
 
Turn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modulesTurn your spaghetti code into ravioli with JavaScript modules
Turn your spaghetti code into ravioli with JavaScript modules
 

Similar to Roman Schejbal: From Madness To Reason

Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsFrancois Zaninotto
 
JavaScript on Rails 튜토리얼
JavaScript on Rails 튜토리얼JavaScript on Rails 튜토리얼
JavaScript on Rails 튜토리얼Sukjoon Kim
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJSAaronius
 
GHC Participant Training
GHC Participant TrainingGHC Participant Training
GHC Participant TrainingAidIQ
 
JavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best PracticesJavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best PracticesSiarhei Barysiuk
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js frameworkBen Lin
 
Java Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdfJava Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdfSudhanshiBakre1
 
Avinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPressAvinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPresswpnepal
 
Security Challenges in Node.js
Security Challenges in Node.jsSecurity Challenges in Node.js
Security Challenges in Node.jsWebsecurify
 
Types End-to-End @ samsara
Types End-to-End @ samsaraTypes End-to-End @ samsara
Types End-to-End @ samsaraStephen Wan
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationAlexander Obukhov
 
Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Arthur Puthin
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
Chaincode Development 區塊鏈鏈碼開發
Chaincode Development 區塊鏈鏈碼開發Chaincode Development 區塊鏈鏈碼開發
Chaincode Development 區塊鏈鏈碼開發HO-HSUN LIN
 

Similar to Roman Schejbal: From Madness To Reason (20)

Bonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node jsBonnes pratiques de développement avec Node js
Bonnes pratiques de développement avec Node js
 
JavaScript on Rails 튜토리얼
JavaScript on Rails 튜토리얼JavaScript on Rails 튜토리얼
JavaScript on Rails 튜토리얼
 
Dependency Management with RequireJS
Dependency Management with RequireJSDependency Management with RequireJS
Dependency Management with RequireJS
 
GHC Participant Training
GHC Participant TrainingGHC Participant Training
GHC Participant Training
 
JavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best PracticesJavaScript and UI Architecture Best Practices
JavaScript and UI Architecture Best Practices
 
How and why i roll my own node.js framework
How and why i roll my own node.js frameworkHow and why i roll my own node.js framework
How and why i roll my own node.js framework
 
Reduxing like a pro
Reduxing like a proReduxing like a pro
Reduxing like a pro
 
JavaScript Core
JavaScript CoreJavaScript Core
JavaScript Core
 
Java Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdfJava Airline Reservation System – Travel Smarter, Not Harder.pdf
Java Airline Reservation System – Travel Smarter, Not Harder.pdf
 
Avinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPressAvinash Kundaliya: Javascript and WordPress
Avinash Kundaliya: Javascript and WordPress
 
Postman On Steroids
Postman On SteroidsPostman On Steroids
Postman On Steroids
 
20150319 testotipsio
20150319 testotipsio20150319 testotipsio
20150319 testotipsio
 
Security Challenges in Node.js
Security Challenges in Node.jsSecurity Challenges in Node.js
Security Challenges in Node.js
 
Types End-to-End @ samsara
Types End-to-End @ samsaraTypes End-to-End @ samsara
Types End-to-End @ samsara
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
PHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generationPHP: GraphQL consistency through code generation
PHP: GraphQL consistency through code generation
 
Spring boot
Spring boot Spring boot
Spring boot
 
Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...Static types on javascript?! Type checking approaches to ensure healthy appli...
Static types on javascript?! Type checking approaches to ensure healthy appli...
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Chaincode Development 區塊鏈鏈碼開發
Chaincode Development 區塊鏈鏈碼開發Chaincode Development 區塊鏈鏈碼開發
Chaincode Development 區塊鏈鏈碼開發
 

More from Develcz

Daniel Steigerwald: WYSIWYG je šik! (když funguje)
Daniel Steigerwald: WYSIWYG je šik! (když funguje)Daniel Steigerwald: WYSIWYG je šik! (když funguje)
Daniel Steigerwald: WYSIWYG je šik! (když funguje)Develcz
 
Ondřej Hlaváček: Životní cyklus featury
Ondřej Hlaváček: Životní cyklus featuryOndřej Hlaváček: Životní cyklus featury
Ondřej Hlaváček: Životní cyklus featuryDevelcz
 
Martin Hassman: Jak se tvoří addony pro World of Warcraft
Martin Hassman: Jak se tvoří addony pro World of WarcraftMartin Hassman: Jak se tvoří addony pro World of Warcraft
Martin Hassman: Jak se tvoří addony pro World of WarcraftDevelcz
 
Ondřej Voves: Jak přepsat monolit do mikroslužeb
Ondřej Voves: Jak přepsat monolit do mikroslužebOndřej Voves: Jak přepsat monolit do mikroslužeb
Ondřej Voves: Jak přepsat monolit do mikroslužebDevelcz
 
Marcel Šulek: Zpraste svoje kódy
Marcel Šulek: Zpraste svoje kódyMarcel Šulek: Zpraste svoje kódy
Marcel Šulek: Zpraste svoje kódyDevelcz
 
Michal Illich: Vývojáři staví letadlo
Michal Illich: Vývojáři staví letadloMichal Illich: Vývojáři staví letadlo
Michal Illich: Vývojáři staví letadloDevelcz
 
Ondřej Kokeš: Zpracování dat z veřejných zdrojů
Ondřej Kokeš: Zpracování dat z veřejných zdrojůOndřej Kokeš: Zpracování dat z veřejných zdrojů
Ondřej Kokeš: Zpracování dat z veřejných zdrojůDevelcz
 
Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...
Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...
Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...Develcz
 
Štěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmysl
Štěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmyslŠtěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmysl
Štěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmyslDevelcz
 
Tomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQL
Tomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQLTomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQL
Tomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQLDevelcz
 
Tomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikací
Tomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikacíTomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikací
Tomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikacíDevelcz
 
Jakub Vrána: Dokazatelná bezpečnost
Jakub Vrána: Dokazatelná bezpečnostJakub Vrána: Dokazatelná bezpečnost
Jakub Vrána: Dokazatelná bezpečnostDevelcz
 
Michal Illich: Zuri aneb Vývojáři staví letadlo
Michal Illich: Zuri aneb Vývojáři staví letadloMichal Illich: Zuri aneb Vývojáři staví letadlo
Michal Illich: Zuri aneb Vývojáři staví letadloDevelcz
 
Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...
Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...
Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...Develcz
 
David Majda: Autoformátování kódu
David Majda: Autoformátování kóduDavid Majda: Autoformátování kódu
David Majda: Autoformátování kóduDevelcz
 
David Grudl: Open source: The Good, the Bad and the Ugly
David Grudl: Open source: The Good, the Bad and the UglyDavid Grudl: Open source: The Good, the Bad and the Ugly
David Grudl: Open source: The Good, the Bad and the UglyDevelcz
 
Ondřej Machulda: Začíná zlatá doba end-to-end testů!
Ondřej Machulda: Začíná zlatá doba end-to-end testů!Ondřej Machulda: Začíná zlatá doba end-to-end testů!
Ondřej Machulda: Začíná zlatá doba end-to-end testů!Develcz
 
Adam Kudrna: Headless WordPress/Drupal
Adam Kudrna: Headless WordPress/DrupalAdam Kudrna: Headless WordPress/Drupal
Adam Kudrna: Headless WordPress/DrupalDevelcz
 
Jaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světě
Jaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světěJaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světě
Jaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světěDevelcz
 
Martin Michálek: Bootstrap 4 - Jednou to muselo přijít
Martin Michálek: Bootstrap 4 - Jednou to muselo přijítMartin Michálek: Bootstrap 4 - Jednou to muselo přijít
Martin Michálek: Bootstrap 4 - Jednou to muselo přijítDevelcz
 

More from Develcz (20)

Daniel Steigerwald: WYSIWYG je šik! (když funguje)
Daniel Steigerwald: WYSIWYG je šik! (když funguje)Daniel Steigerwald: WYSIWYG je šik! (když funguje)
Daniel Steigerwald: WYSIWYG je šik! (když funguje)
 
Ondřej Hlaváček: Životní cyklus featury
Ondřej Hlaváček: Životní cyklus featuryOndřej Hlaváček: Životní cyklus featury
Ondřej Hlaváček: Životní cyklus featury
 
Martin Hassman: Jak se tvoří addony pro World of Warcraft
Martin Hassman: Jak se tvoří addony pro World of WarcraftMartin Hassman: Jak se tvoří addony pro World of Warcraft
Martin Hassman: Jak se tvoří addony pro World of Warcraft
 
Ondřej Voves: Jak přepsat monolit do mikroslužeb
Ondřej Voves: Jak přepsat monolit do mikroslužebOndřej Voves: Jak přepsat monolit do mikroslužeb
Ondřej Voves: Jak přepsat monolit do mikroslužeb
 
Marcel Šulek: Zpraste svoje kódy
Marcel Šulek: Zpraste svoje kódyMarcel Šulek: Zpraste svoje kódy
Marcel Šulek: Zpraste svoje kódy
 
Michal Illich: Vývojáři staví letadlo
Michal Illich: Vývojáři staví letadloMichal Illich: Vývojáři staví letadlo
Michal Illich: Vývojáři staví letadlo
 
Ondřej Kokeš: Zpracování dat z veřejných zdrojů
Ondřej Kokeš: Zpracování dat z veřejných zdrojůOndřej Kokeš: Zpracování dat z veřejných zdrojů
Ondřej Kokeš: Zpracování dat z veřejných zdrojů
 
Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...
Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...
Patrick Zandl: Open source software, hardware, 3D tiskárny a tvrdý business -...
 
Štěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmysl
Štěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmyslŠtěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmysl
Štěpán Bechynský: Hardware pro IoT projekty nejen pro hobby, ale i pro průmysl
 
Tomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQL
Tomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQLTomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQL
Tomáš Vondra: Paralelizace dotazu a partitioning v PostgreSQL
 
Tomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikací
Tomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikacíTomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikací
Tomáš Zvěřina: Flutter.io - multiplatformní vývoj mobilních aplikací
 
Jakub Vrána: Dokazatelná bezpečnost
Jakub Vrána: Dokazatelná bezpečnostJakub Vrána: Dokazatelná bezpečnost
Jakub Vrána: Dokazatelná bezpečnost
 
Michal Illich: Zuri aneb Vývojáři staví letadlo
Michal Illich: Zuri aneb Vývojáři staví letadloMichal Illich: Zuri aneb Vývojáři staví letadlo
Michal Illich: Zuri aneb Vývojáři staví letadlo
 
Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...
Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...
Ondřej Šika: Docker, Traefik a CI - Mějte nasazené všeny větve na kterých pra...
 
David Majda: Autoformátování kódu
David Majda: Autoformátování kóduDavid Majda: Autoformátování kódu
David Majda: Autoformátování kódu
 
David Grudl: Open source: The Good, the Bad and the Ugly
David Grudl: Open source: The Good, the Bad and the UglyDavid Grudl: Open source: The Good, the Bad and the Ugly
David Grudl: Open source: The Good, the Bad and the Ugly
 
Ondřej Machulda: Začíná zlatá doba end-to-end testů!
Ondřej Machulda: Začíná zlatá doba end-to-end testů!Ondřej Machulda: Začíná zlatá doba end-to-end testů!
Ondřej Machulda: Začíná zlatá doba end-to-end testů!
 
Adam Kudrna: Headless WordPress/Drupal
Adam Kudrna: Headless WordPress/DrupalAdam Kudrna: Headless WordPress/Drupal
Adam Kudrna: Headless WordPress/Drupal
 
Jaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světě
Jaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světěJaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světě
Jaroslav Tulach: GraalVM - z vývoje nejrychlejšího virtuálního stroje na světě
 
Martin Michálek: Bootstrap 4 - Jednou to muselo přijít
Martin Michálek: Bootstrap 4 - Jednou to muselo přijítMartin Michálek: Bootstrap 4 - Jednou to muselo přijít
Martin Michálek: Bootstrap 4 - Jednou to muselo přijít
 

Recently uploaded

Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfStefano Stabellini
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanyChristoph Pohl
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityNeo4j
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based projectAnoyGreter
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtimeandrehoraa
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 

Recently uploaded (20)

Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Xen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdfXen Safety Embedded OSS Summit April 2024 v4.pdf
Xen Safety Embedded OSS Summit April 2024 v4.pdf
 
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte GermanySuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
SuccessFactors 1H 2024 Release - Sneak-Peek by Deloitte Germany
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
EY_Graph Database Powered Sustainability
EY_Graph Database Powered SustainabilityEY_Graph Database Powered Sustainability
EY_Graph Database Powered Sustainability
 
MYjobs Presentation Django-based project
MYjobs Presentation Django-based projectMYjobs Presentation Django-based project
MYjobs Presentation Django-based project
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
SpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at RuntimeSpotFlow: Tracking Method Calls and States at Runtime
SpotFlow: Tracking Method Calls and States at Runtime
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 

Roman Schejbal: From Madness To Reason

  • 1. from Madness to Reason @romanschejbal from React to ReasonReact
  • 2. SYNTAX & TOOLCHAIN FOR OCAML
  • 6. OCaml? Why should I care? 🤔
  • 10. Compiler Errors We've found a bug for you! /workspace/reason/src/Student.re 20:30 19 │ let age = 2; 20 │ let greeting = greet(Student(1)); 21 │ 22 │ Js.log(greeting); This has type: int But somewhere wanted: string You can convert a int to a string with string_of_int.
  • 11. Good Support For Immutable Programming ✔
  • 12. Automatic Type Inference (less type definitions)
  • 15. let name = "Reason"; let age = 2; let greet = () => "Hello World!"; Language Basics
  • 16. Algebraic data types type name = option(string); /* None | Some(“Reason”) */ type state = { items: array(string), length: number }; type schoolPerson = | Teacher | Director | Student(string);
  • 17. type schoolPerson = Teacher | Director | Student(string); let greet = stranger => switch (stranger) { | Teacher => "Hey professor!" | Director => "Hello director." | Student("Richard") => "Still here Ricky?" | Student(anyOtherName) => "Hey, " ++ anyOtherName ++ "." }; greet(Teacher); /* Hey professor! */ greet(Student("OCaml")); /* Hey, OCaml. */ Variants & Pattern Matching
  • 18. Pattern Matching Exhaustiveness Warning number 8 /workspace/reason/src/Student.re 7:3-12:3 5 │ 6 │ let greet = stranger => 7 │ switch (stranger) { 8 │ | Teacher => "Hey professor!" . │ ... 11 │ /* | Student(anyOtherName) => "Hey " ++ anyOtherName ++ "." */ 12 │ }; 13 │ 14 │ print_endline(greet(Teacher)); You forgot to handle a possible value here, for example: Student ""
  • 19.
  • 20. type userT = option(string); let userOne = Some("X"); let userTwo = None; let printPlayerName = player => switch (player) { | Some(name) => "Logged in as " ++ name | None => "Not logged in" }; Option type
  • 21. Why Reason then? 🤔 “We want people to be able to use powerful, well- typed languages at work, not just in their free time.” - Jordan Walke
  • 23.
  • 24.
  • 25. How Do I Start 🧐
  • 27. flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | |- store.js | |- App.js | |- index.js | package.json | bsconfig.json | yarn.lock
  • 28. flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | |- store.js | |- App.js | |- index.js | package.json | bsconfig.json | yarn.lock yarn add bs-platform reason-react
  • 29. bsconfig.json { "name": "my-project", "namespace": true, "sources": [ { "dir": "src", "subdirs": true } ], "package-specs": { "module": "es6-global", "in-source": true }, "suffix": ".bs.js", "bs-dependencies": ["reason-react"], "reason": { "react-jsx": 2 } } flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | |- store.js | |- App.js | |- index.js | package.json | bsconfig.json | yarn.lock
  • 30. package.json { "name": "from-react-to-reason", "version": "0.1.0", "private": true, "dependencies": { "bs-platform": "^3.0.0", "flow-bin": "^0.72.0", "react": "^16.3.2", "react-dom": "^16.3.2", "react-redux": "^5.0.7", "react-scripts": "1.1.4", "reason-react": "^0.4.1", "redux": "^4.0.0", "redux-thunk": "^2.2.0" }, "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "bsb": "bsb -make-world -w" } } flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | |- store.js | |- App.js | |- index.js | package.json | bsconfig.json | yarn.lock "bsb": "bsb -make-world -w"
  • 31. src/Types.re [@bs.deriving jsConverter] type flightInfo = { airline: string, price: int, duration: float, }; flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock Record Type
  • 32. src/Types.bs.js // Generated by BUCKLESCRIPT VERSION 3.0.0, PLEASE EDIT WITH CARE function flightInfoToJs(param) { return { airline: param[ /* airline */0], price: param[ /* price */1], duration: param[ /* duration */2] }; } function flightInfoFromJs(param) { return /* record */[ /* airline */param.airline, /* price */param.price, /* duration */param.duration ]; } export { flightInfoToJs , flightInfoFromJs , } /* No side effect */ flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 33. src/state/reducer/index.js import { type actionT, REQUEST_FLIGHTS, RECEIVE_FLIGHTS, FAILURE_FLIGHTS, } from ' ../action'; const initialState = { loading: false, flights: [], error: null, }; export default (state = initialState, action) => { switch (action.type) { case REQUEST_FLIGHTS: return { ...state, loading: true }; case RECEIVE_FLIGHTS: return { ...state, loading: false, flights: action.payload.flights }; case FAILURE_FLIGHTS: return { ...state, error: action.payload.error }; default: return state; } }; flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 34. src/state/reducer/Reducer.re type flightsData = array(Types.flightInfo); [@bs.deriving jsConverter] type state = { loading: bool, flights: flightsData, error: option(Js.Exn.t) }; let initialState = { loading: false, flights: [ ||], error: None }; let default = (state, action) => switch (action ##_type) { | "REQUEST_FLIGHTS" => { ...state, loading: true} | "RECEIVE_FLIGHTS" => { ...state, flights: Array.map(Types.flightInfoFromJs, action ##payload ##flights), loading: false, } | "FAILURE_FLIGHTS" => { ...state, error: action ##payload ##error} }; flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 35. src/state/reducer/Reducer.re Warning number 8 /Users/roman/workspace/from-react-to-reason/src/state/reducer/Reducer.re 21:3-30:3 19 │ 20 │ let default = (state, action) => 21 │ switch (action##_type) { 22 │ | "REQUEST_FLIGHTS" => {...state, loading: true} . │ ... 29 │ | “FAILURE_FLIGHTS" => {...state, error: action##payload##error} 30 │ }; 31 │ 32 │ /* let default = (state, action) => { You forgot to handle a possible value here, for example: ""
  • 36. src/state/reducer/Reducer.re type flightsData = array(Types.flightInfo); type state = { loading: bool, flights: flightsData, error: option(Js.Exn.t) }; let initialState = { loading: false, flights: [ ||], error: None }; let default = (state, action) => switch (action ##_type) { | "REQUEST_FLIGHTS" => { ...state, loading: true} | "RECEIVE_FLIGHTS" => { ...state, flights: Array.map(Types.flightInfoFromJs, action ##payload ##flights), loading: false, } | "FAILURE_FLIGHTS" => { ...state, error: action ##payload ##error} | _ => state }; flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock | _ => state
  • 37. src/state/action/index.js export const REQUEST_FLIGHTS = 'REQUEST_FLIGHTS'; export const RECEIVE_FLIGHTS = 'RECEIVE_FLIGHTS'; export const FAILURE_FLIGHTS = 'FAILURE_FLIGHTS'; export const fetchFlights = (where, when) => ( dispatch ) => { dispatch(requestFlights()); setTimeout( () => dispatch( receiveFlights([ { airline: 'British Airways', price: 390, duration: 3.5 }, { airline: 'KLM', price: 340, duration: 2.2 } ]) ), 3000 ); }; const requestFlights = () => ({ type: REQUEST_FLIGHTS }); const receiveFlights = (flights: Array<Object>) => ({ type: RECEIVE_FLIGHTS, payload: { flights } }); const failureFlights = (error: Error) => ({ type: FAILURE_FLIGHTS, payload: { error } }); flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 38. src/state/action/Actions.re let fetchFlights = (from, where, when) => (. dispatch) => { dispatch(requestFlights(from, where, when)); Js.Global.setTimeout( () => dispatch( receiveFlights( [| {airline: "British Airways", price: 390, duration: 3.5}, {airline: "KLM", price: 340, duration: 2.2}, |]), ), 3000, ); }; let requestFlights = (from, where, when) => { "type": "REQUEST_FLIGHTS", "payload": { "from": from, "where": where, "when": when, }, }; let receiveFlights = flights => { "type": "RECEIVE_FLIGHTS", "payload": { "flights": flights, }, }; ... flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | | |- Actions.re | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 39. src/state/store.js import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducer/Reducer.bs'; const initialState = undefined; export default () => createStore( rootReducer, applyMiddleware(thunk), initialState ); flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | | |- Actions.re | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 40. What have we gained? 1. Can’t mess up our state shape Can we get more?
  • 41. src/state/action/Actions.re let fetchFlights = (from, where, when) => (. dispatch) => { dispatch(requestFlights(from, where, when)); Js.Global.setTimeout( () => dispatch( receiveFlights( [| {airline: "British Airways", price: 390, duration: 3.5}, {airline: "KLM", price: 340, duration: 2.2}, |]), ), 3000, ); }; let requestFlights = (from, where, when) => { "type": "REQUEST_FLIGHTS", "payload": { "from": from, "where": where, "when": when, }, }; let receiveFlights = flights => { "type": "RECEIVE_FLIGHTS", "payload": { "flights": flights, }, }; let failureFlights = error => { "type": "FAILURE_FLIGHTS", "payload": { "error": error, }, }; flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | | |- Actions.re | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 42. src/state/action/Actions.re type from = string; type where = string; type when = string; [@bs.deriving accessors] type action = | RequestFlights(from, where, when) | ReceiveFlights(array(Types.flightInfo)) | FailureFlights(Js.Exn.t); let fetchFlights = (from, where, when) => (. dispatch) => { dispatch(RequestFlights(from, where, when)); Js.Global.setTimeout( () => dispatch( ReceiveFlights( [| {airline: "British Airways", price: 390, duration: 3.5}, {airline: "KLM", price: 340, duration: 2.2}, |]), ), 3000, ); }; flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | | |- Actions.re | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 43. src/state/action/Reducer.re type flightsData = array(Types.flightInfo); [@bs.deriving jsConverter] type state = { loading: bool, flights: flightsData, error: option(Js.Exn.t), }; let initialState = { loading: false, flights: [ ||], error: None, }; let default = (state, action) => { Actions.( switch (action) { | RequestFlights(_, _, _) => { ...state, loading: true} | ReceiveFlights(flights) => { ...state, flights} | FailureFlights(error) => { ...state, error: Some(error)} } ) }; flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | | |- Actions.re | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 44. src/state/store.js import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import rootReducer from './reducer/Reducer.bs'; const fromReasonToJs = store => next => action => { if (action.tag !== undefined) { // reason action const { tag } = action; action = { type: `REASON_ACTION_${tag}`, tag, reasonAction: action }; } next(action); }; const reasonReducer = reducer => (state, action) => { if (action.reasonAction) return reducer(state, action.reasonAction); return reducer(state, { ...action, tag: -1 }); }; const initialState = undefined; export default () => createStore( reasonReducer(rootReducer), applyMiddleware(thunk, fromReasonToJs), initialState ); flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | |- state/ | | |- action/ | | | |- index.js | | | |- Actions.re | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 45. src/components/FlightList.re open ReasonReact; let component = statelessComponent("FlightsList"); let make = (~data, _children) => { ...component, render: _self => <div> ( Array.map( flightInfo => <div> <h2> (string(flightInfo.airline)) </h2> <p> (string("Price: $" ++ string_of_int(flightInfo.price))) ( string( " | Duration: " ++ string_of_float(flightInfo.duration) ++ "hours", ) ) </p> </div>, data, ) |> array ) </div>, }; let default = wrapReasonForJs(~component, jsProps => make(~data=jsProps ##data, jsProps ##children) ); flight-search/ |- public/ |- node_modules/ |- public/ |- src/ | |- components/ | | |- flight-list.js | | | |- FlightList.js | |- state/ | | |- action/ | | | |- index.js | | | |- Actions.re | | |- reducer/ | | | |- index.js | | | |- Reducer.re | | |- store.js | |- App.js | |- index.js | |- Types.re | package.json | bsconfig.json | yarn.lock
  • 46. What have we gained? 1. Can’t mess up our state shape 2. Can’t forget to handle actions 3. Can’t forget to handle edge cases
  • 47. Not covered… • Rendering a JS component from a Reason component • Using Variants for async stuff i.e. [@bs.module] external myJSComponent : ReasonReact.reactClass = “./my-js-component“; let make = (~name: string, ~age: option(int)=?, children) => ReasonReact.wrapJsForReason( ~reactClass=myJSComponent, ~props={"name": name, "age": Js.Nullable.fromOption(age)}, children, ); type async('a) = | Idle | Loading | Success('a) | Error(Js.Exn.t); type action = | Tick(unit) | Flights(Types.(async(array(flightInfo)))); http://blog.jenkster.com/2016/06/how-elm-slays-a-ui-antipattern.html
  • 48.