extending redux in the server side

87
Nacho Martín @nacmartin AgentConf January 2018 Extending Redux in the Server Side

Upload: ignacio-martin

Post on 16-Mar-2018

161 views

Category:

Software


1 download

TRANSCRIPT

Page 1: Extending Redux in the Server Side

Nacho Martín @nacmartin

AgentConf January 2018

Extending Redux in the Server Side

Page 2: Extending Redux in the Server Side

Nacho Martín (Spanish parents do actually pick this name for their kids)

I write code at Limenius.

We build tailor-made projects, and provide consultancy and formation.

We organize React Alicante.

And we are very happy with React and React Native.

Page 3: Extending Redux in the Server Side

http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/

Page 4: Extending Redux in the Server Side

http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/

Page 5: Extending Redux in the Server Side

Redux: Three principles

The state of the whole application is stored in an object tree within a single store.

The only way to change the state is to emit an action, an object describing what happened.

To specify how the state tree is transformed by actions, you write pure reducers.

Page 6: Extending Redux in the Server Side

Redux as async reduce

state = actions.reduce(reducer, initialState)

newState = reducer(action, state)

Page 7: Extending Redux in the Server Side

A particular way of thinking.

Useful to model certain problems.

What are we going to talk about

Page 8: Extending Redux in the Server Side

Photo by Tim Trad

MAP

TERRITORY&

Page 9: Extending Redux in the Server Side
Page 10: Extending Redux in the Server Side

PLAN

TERRITORY&

Page 11: Extending Redux in the Server Side

Typical case

Create

Read

Update

Delete

If my DB has…

Page 12: Extending Redux in the Server Side

Typical case

Create

Read

Update

Delete

If my DB has… …and my REST API has…

POST

GET

PUT

DELETE+

Page 13: Extending Redux in the Server Side

Typical case

Create

Read

Update

Delete

If my DB has… …and my REST API has…

POST

GET

PUT

DELETE+ =

…my project will be…

Page 14: Extending Redux in the Server Side

by Adam Morse

TABLES, TABLES EVERYWHERE 🎉

Page 15: Extending Redux in the Server Side

“Chat tutorial paradigm”

SENDHi there! SEND

SERVERemit(‘chat_message’, ‘hi there!’)

(Whenever there is a websocket)

Page 16: Extending Redux in the Server Side

“Chat tutorial paradigm”

SEND SEND

SERVERemit(‘chat_message’, ‘hi there!’)

socket.on(‘chat_message', function(msg){ io.emit(‘chat_message', msg); });

(Whenever there is a websocket)

Page 17: Extending Redux in the Server Side

“Chat tutorial paradigm”

SEND SEND

Hi there!

SERVERemit(‘chat_message’, ‘hi there!’)

socket.on(‘chat_message', function(msg){ io.emit(‘chat_message', msg); });

socket.on(‘chat_message', function(msg){ addMessage(msg)); });

(Whenever there is a websocket)

Page 18: Extending Redux in the Server Side

Typically we also want

SEND SEND

Hi there!

SERVERemit(‘chat_message’, ‘hi there!’)

socket.on(‘chat_message', function(msg){ io.emit(‘chat_message', msg); });

socket.on(‘chat_message', function(msg){ addMessage(msg)); });

store(‘hi there!’)

Page 19: Extending Redux in the Server Side

by Mathyas Kurmann

MESSAGES, MESSAGES EVERYWHERE 🎉

Page 20: Extending Redux in the Server Side

Multiple users manipulate the same resource.

And they need to be notified in real time of the changes.

Our particular case study

Editor for nutritionists that several users can manipulate in collaboration.

Games (cards, domino, quizzes…).

Page 21: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

Page 22: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

Event

Page 23: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

Event

Page 24: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Event’

Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

{type: answer player: 1, answer:3, correct: false}

Event

Page 25: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Event’

Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

{type: answer player: 1, answer:3, correct: false}

Event

Mark answer as selected

Page 26: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

Event

Page 27: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Event’

Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

{type: new_question question: q}

Event

Page 28: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Event’

Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

{type: new_question question: q}

Event

Change question

Page 29: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

Event

Page 30: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Event’

Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

{type: new_scores scores: sc}

Event

Page 31: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

User picks answer 3

Event’

Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?

Mark answer as selected

SERVER CLIENTCLIENT

State State’ State

{type: answer answer:3}

{type: new_scores scores: sc}

Event

Update scores

Page 32: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

Events’

SERVER CLIENT

State State’Events

Two vocabularies of eventsTwo representations of the stateTwo ways of calculating the state

Page 33: Extending Redux in the Server Side

Example: Quiz Game (Multiplayer)

Events’

SERVER CLIENT

State State’Events

Two applications :_(

Page 34: Extending Redux in the Server Side

Best situation

User disconnected! 💀 SERVERCLIENT

State State’🎉

Page 35: Extending Redux in the Server Side

Best situation

User reconnected! SERVERCLIENT

State State’Plz give me the state

Page 36: Extending Redux in the Server Side

Best situation

SERVERCLIENT

State State’{get_state: state}

🎉

Page 38: Extending Redux in the Server Side

SERVER

State

CLIENT

State

CLIENT

State

Page 39: Extending Redux in the Server Side

SERVER

State

CLIENT

State

CLIENT

State

Event

Page 40: Extending Redux in the Server Side

SERVER

State

CLIENT

State

CLIENT

State

Event

Update state

Page 41: Extending Redux in the Server Side

SERVER

State

CLIENT

State

CLIENT

State

Event

State

Update state

State

Page 42: Extending Redux in the Server Side

Making the backend play well with Redux

A part of the client’s Redux state lives in the server.

The client changes it sending events to the server.

The server pushes (slices of) the state to the clients.

Page 43: Extending Redux in the Server Side

Let’s build the simplest example

Page 44: Extending Redux in the Server Side

With Redux directly in node.js

Page 45: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Page 46: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Events

Store

State

Reducers

Client Server

Page 47: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Events

Store

State

Reducers

Client Server

Page 48: Extending Redux in the Server Side

<Grid> {board.map((row, idxRow) => ( <Row idx={idxRow} key={idxRow}> {row.map((tile, idx) => ( <Tile onClick={() => this.socket.emit("game:play", { x: idx, y: idxRow })} key={idx} idx={idx} tile={tile} /> ))} </Row> ))} </Grid>

Client

Page 49: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Events

Store

State

Reducers

Client Server

Page 50: Extending Redux in the Server Side

io.on("connection", function(socket) { //… socket.on("game:play", function(data) { store.dispatch({ type: GAME_PLAY, x: data.x, y: data.y }); }); socket.on("game:reset", function(data) { store.dispatch({ type: GAME_RESET }); });});

Server

Page 51: Extending Redux in the Server Side

const reducer = function(state = initialState, action = {}) { switch (action.type) { case GAME_PLAY: const { stateAfterPlayer, waitingForOpponent } = makePlayerMove(state, { x: action.x, y: action.y }); if (!waitingForOpponent) { return stateAfterPlayer; } return makeAIMove(stateAfterPlayer); case GAME_RESET: return initialState; default: return state; }};

Server

Page 52: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Events

Store

State

Reducers

Client Server

Page 53: Extending Redux in the Server Side

observeStore( store, state => state, state => { socket.emit("game_update", state) } );

function observeStore(store, select, onChange) { let currentState;

function handleChange() { let nextState = select(store.getState()); if (nextState !== currentState) { currentState = nextState; onChange(currentState); } }

let unsubscribe = store.subscribe(handleChange); handleChange(); return unsubscribe;}

Server

Page 54: Extending Redux in the Server Side

componentDidMount() { const { dispatch } = this.props; let socket = ioClient("http://localhost:3080"); socket.on("game_update", gameState => dispatch(updateGame(gameState))); }

Client

Page 55: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Events

Store

State

Reducers

Client Server

Page 56: Extending Redux in the Server Side

export default function reducer(state = initialState, action = {}) { switch (action.type) { case GAME_UPDATE: return { ...state, board: action.game.board, phase: action.game.phase };

default: return state; }}

export function updateGame(game) { return { type: GAME_UPDATE, game };}

Client

Page 57: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Events

Store

State

Reducers

Client Server

Page 58: Extending Redux in the Server Side

const mapStateToProps = state => ({ board: state.board, phase: state.phase });

export default connect(mapStateToProps)(Board);

Client

Page 59: Extending Redux in the Server Side

With Elixir OTP

Page 60: Extending Redux in the Server Side

Erlang: The Movie

Hello Mike.

Page 61: Extending Redux in the Server Side

Used in

Databases, gaming, telecom, message passing…

“Erlang is a programming language used to build massively scalable soft real-time systems with requirements on high availability”

Page 62: Extending Redux in the Server Side
Page 63: Extending Redux in the Server Side

😍OPEN TELECOM PLATFORM😍

Page 64: Extending Redux in the Server Side

Supervisor

GenServerGenServerSupervisor

GenServerGenServer GenServer

OTP Supervision trees

Page 65: Extending Redux in the Server Side

Gen Server callbacks

defmodule Tictactoe.GameServer do use GenServer

#Callbacks def init(args) do {:ok, state} end

def handle_cast(request, state) do {:noreply, new_state} endend

state = actions.reduce(reducer, initialState)

newState = reducer(action, state);

Page 66: Extending Redux in the Server Side

Views

Actions

Reducers

StateStore

Events

GenServer

State

Callbacks

Client Server

Page 67: Extending Redux in the Server Side

defmodule TictactoeWeb.GameChannel do use Phoenix.Channel

def join("game", _message, socket) do game = Tictactoe.GameServer.getGameState() {:ok, game, socket} end

def handle_in("game:play", %{"x" => x, "y" => y}, socket) do Tictactoe.GameServer.play(x, y) {:noreply, socket} end

def handle_in("game:reset", _, socket) do Tictactoe.GameServer.reset() {:noreply, socket} endend

Page 68: Extending Redux in the Server Side

def init(:ok) do {:ok, %State{}} end

const reducer = function(state = initialState, action = {}) { switch (action.type) { //… default: return state; }};

Page 69: Extending Redux in the Server Side

const reducer = function(state, action) { switch (action.type) { //.. case GAME_RESET: return initialState; //… }};

def handle_cast(%{:action => :reset}, _state) do state = %State{} Endpoint.broadcast(“game", “game_update", serialize_game(state)) {:noreply, state} end

Page 70: Extending Redux in the Server Side

def handle_cast(%{:action => :play, :x => x, :y => y}, state) do case can_move(state, x, y) do :true -> state1 = put_in state.board[y][x], "X" state2 = state |> check_finished |> make_random_move |> check_finished Endpoint.broadcast( “game", “game_update", serialize_game(state2)) state2 :false -> state end {:noreply, state} end

const reducer = function(state, action) { switch (action.type) { case GAME_PLAY: const { stateAfterPlayer, waitingForOpponent } = makePlayerMove(state, { x: action.x, y: action.y }); if (!waitingForOpponent) { return stateAfterPlayer; } return makeAIMove(stateAf); //.. }};

Page 71: Extending Redux in the Server Side

Demo

https://github.com/Limenius/tictactoe

Page 72: Extending Redux in the Server Side

CAN WE THINK ABOUT THIS

AS AN IN-MEMORY DATABASE? 🤔

by Sindre Aalberg

Page 73: Extending Redux in the Server Side

And can we think about this as Event Sourcing?

CLIENT

State

SERVER

Page 74: Extending Redux in the Server Side

And can we think about this as Event Sourcing?

CLIENT

State

Events

SERVER

Page 75: Extending Redux in the Server Side

And can we think about this as Event Sourcing?

CLIENT

State

Events

SERVERLog

Page 76: Extending Redux in the Server Side

And can we think about this as Event Sourcing?

CLIENT

State

Events

SERVER

View

Log

Page 77: Extending Redux in the Server Side

Queries

And can we think about this as Event Sourcing?

CLIENT

State

Events

SERVER

View

Log

Page 78: Extending Redux in the Server Side

Queries

And can we think about this as Event Sourcing?

CLIENT

State

Events

SERVER

View

Log

Another view

Page 79: Extending Redux in the Server Side

Queries

And can we think about this as Event Sourcing?

CLIENT

State

Events

SERVERLog

Another view

View (State)

Page 80: Extending Redux in the Server Side

And can we think about this as Event Sourcing?

CLIENT

State

Events

Subscribe

SERVERLog

Another view

View (State)

Page 81: Extending Redux in the Server Side

FrontendBackendDatabase

THE GAME OF CRUD

Page 82: Extending Redux in the Server Side

FrontendBackendDatabase

THE GAME OF CRUD

Page 83: Extending Redux in the Server Side

FrontendBackendDatabase

THE GAME OF CRUD

Page 84: Extending Redux in the Server Side

FrontendBackendDatabase

THE GAME OF CRUD

Page 85: Extending Redux in the Server Side

FrontendBackendDatabase

LET’S PLAY A DIFFERENT GAME

Page 86: Extending Redux in the Server Side

FrontendBackendDatabase

LET’S PLAY A DIFFERENT GAME