SlideShare une entreprise Scribd logo
1  sur  87
React+Redux @ Scale
InfoQ.com: News & Community Site
• 750,000 unique visitors/month
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• News 15-20 / week
• Articles 3-4 / week
• Presentations (videos) 12-15 / week
• Interviews 2-3 / week
• Books 1 / month
Watch the video with slide
synchronization on InfoQ.com!
https://www.infoq.com/presentations/
react-redux-scale
Presented at QCon New York
www.qconnewyork.com
Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
@dcousineau
Rules
“Rules”
Scalability is the capability of a system, network, or process
to handle a growing amount of work, or its potential to be
enlarged to accommodate that growth.
– Wikipedia
Part 1: React
Rule: Components should be stateless
Reality: State is the enemy, but also inevitable
onClick(e) {
const value = e.target.value;
const formatted = value.toUpperCase();
this.setState({value: formatted});
}
onClick() {
this.setState((previousState, currentProps) => {
return {
show: !previousState.show,
};
});
}
onClick(e) {
this.setState({value: e.target.value});
this.props.onChange(this.state.value);
}
onClick(e) {
this.setState({value: e.target.value}, () => {
this.props.onChange(this.state.value);
});
}
Rule: Don’t use Context, it hides complexity
Reality: Sometimes complexity should be hidden
class TextCard extends React.Component {
static contextTypes = {
metatypes: React.PropTypes.object,
};
render() {
const {cardData} = this.props;
const {metatypes} = this.context;
return (
<div>
The following is either editable or displayed:
<metatypes.text value={cardData.text} onChange={this.props.onChange} />
</div>
)
}
}
function selectCardComponent(cardData) {
switch (cardData.type) {
case 'text': return TextCard;
default: throw new Error(`Invalid card type ${cardData.type}`);
}
}
class TextCard extends React.Component {
static contextTypes = {
metatypes: React.PropTypes.object,
};
render() {
const {cardData} = this.props;
const {metatypes} = this.context;
return (
<div>
The following is either editable or displayed:
<metatypes.text value={cardData.text} onChange={this.props.onChange} />
</div>
)
}
}
function selectCardComponent(cardData) {
switch (cardData.type) {
case 'text': return TextCard;
default: throw new Error(`Invalid card type ${cardData.type}`);
}
}
const metatypesEdit = {
text: class extends React.Component {
render() {
return <input type="text" {...this.props} />;
}
}
}
const metatypesView = {
text: class extends React.Component {
render() {
return <span>{this.props.value}</span>;
}
}
}
class CardViewer extends React.Component {
static childContextTypes = {
metatypes: React.PropTypes.object
};
getChildContext() {
return {metatypes: metatypesView};
}
render() {
const {cardData} = this.props;
const CardComponent = selectCardComponent(cardData);
return <CardComponent cardData={cardData} />
}
}
class CardEditor extends React.Component {
static childContextTypes = {
metatypes: React.PropTypes.object
};
getChildContext() {
return {metatypes: metatypesEdit};
}
render() {
const {cardData} = this.props;
const CardComponent = selectCardComponent(cardData);
return <CardComponent cardData={cardData} />
}
}
Part 2: Redux
Rule: “Single source of truth” means all state in the store
Reality: You can have multiple “single sources”
this.state.checked = true;
this.props.checked = true; this.props.checked = true; this.props.checked = true;
this.state.checked = true;
this.props.checked = true; this.props.checked = true; this.props.checked = true;
this.props.checked = true; checked: true
connect()();
window.location.*
Rule: Side effects should happen outside the Redux cycle
Reality: This doesn’t mean you can’t have callbacks
function persistPostAction(post, callback = () => {}) {
return {
type: 'PERSIST_POST',
post,
callback
};
}
function *fetchPostsSaga(action) {
const status = yield putPostAPI(action.post);
yield put(persistPostCompleteAction(status));
yield call(action.callback, status);
}
class ComposePost extends React.Component {
onClickSubmit() {
const {dispatch} = this.props;
const {post} = this.state;
dispatch(persistPostAction(post, () => this.displaySuccessBanner()));
}
}
class ViewPostPage extends React.Component {
componentWillMount() {
const {dispatch, postId} = this.props;
dispatch(fetchPostAction(postId, () => this.logPageLoadComplete()));
}
}
Rule: Redux stores must be normalized for performance
Reality: You must normalize to reduce complexity
https://medium.com/@dcousineau/advanced-redux-entity-normalization-f5f1fe2aefc5
{
byId: {
...entities
},
keyWindows: [`${keyWindowName}`],
[keyWindowName]: {
ids: ['id0', ..., 'idN'],
...meta
}
}
{
byId: {
'a': userA, 'b': userB, 'c': userC, 'd': userD
},
keyWindows: ['browseUsers', 'allManagers'],
browseUsers: {
ids: ['a', 'b', 'c'],
isFetching: false,
page: 1,
totalPages: 10,
next: '/users?page=2',
last: '/users?page=10'
},
allManagers: {
ids: ['d', 'a'],
isFetching: false
}
}
function selectUserById(store, userId) {
return store.users.byId[userId];
}
function selectUsersByKeyWindow(store, keyWindow) {
return store.users[keyWindow].ids.map(userId => selectUserById(store, userId));
}
function fetchUsers({query}, keyWindow) {
return {
type: FETCH_USERS,
query,
keyWindow
};
}
function fetchManagers() {
return fetchUsers({query: {isManager: true}}, 'allManager');
}
function receiveEntities(entities, keyWindow) {
return {
type: RECEIVE_ENTITIES,
entities,
keyWindow
};
}
function reducer(state = defaultState, action) {
switch(action.type) {
case FETCH_USERS:
return {
...state,
keyWindows: uniq([...state.keyWindows, action.keyWindow]),
[action.keyWindow]: {
...state[action.keyWindow],
isFetching: true,
query: action.query
}
};
case RECEIVE_ENTITIES:
return {
...state,
byId: {
...state.byId,
...action.entities.users.byId
},
keyWindows: uniq([...state.keyWindows, action.keyWindow]),
[action.keyWindow]: {
...state[action.keyWindow],
isFetching: false,
ids: action.entities.users.ids
}
};
}
}
function reducer(state = defaultState, action) {
switch(action.type) {
case FETCH_USERS:
return {
...state,
keyWindows: uniq([...state.keyWindows, action.keyWindow]),
[action.keyWindow]: {
...state[action.keyWindow],
isFetching: true,
query: action.query
}
};
case RECEIVE_ENTITIES:
return {
...state,
byId: {
...state.byId,
...action.entities.users.byId
},
keyWindows: uniq([...state.keyWindows, action.keyWindow]),
[action.keyWindow]: {
...state[action.keyWindow],
isFetching: false,
ids: action.entities.users.ids
}
};
}
}
function selectUsersAreFetching(store, keyWindow) {
return !!store.users[keyWindow].isFetching;
}
function selectManagersAreFetching(store) {
return selectUsersAreFetching(store, 'allManagers');
}
function reducer(state = defaultState, action) {
switch(action.type) {
case UPDATE_USER:
return {
...state,
draftsById: {
...state.draftsById,
[action.user.id]: action.user
}
};
case RECEIVE_ENTITIES:
return {
...state,
byId: {
...state.byId,
...action.entities.users.byId
},
draftsById: {
...omit(state.draftsById, action.entities.users.byId)
},
keyWindows: uniq([...state.keyWindows, action.keyWindow]),
[action.keyWindow]: {
...state[action.keyWindow],
isFetching: false,
ids: action.entities.users.ids
}
};
}
}
function reducer(state = defaultState, action) {
switch(action.type) {
case UPDATE_USER:
return {
...state,
draftsById: {
...state.draftsById,
[action.user.id]: action.user
}
};
case RECEIVE_ENTITIES:
return {
...state,
byId: {
...state.byId,
...action.entities.users.byId
},
draftsById: {
...omit(state.draftsById, action.entities.users.byId)
},
keyWindows: uniq([...state.keyWindows, action.keyWindow]),
[action.keyWindow]: {
...state[action.keyWindow],
isFetching: false,
ids: action.entities.users.ids
}
};
}
}
function selectUserById(store, userId) {
return store.users.draftsById[userId] || store.users.byId[userId];
}
function reducer(state = defaultState, action) {
switch(action.type) {
case UNDO_UPDATE_USER:
return {
...state,
draftsById: {
...omit(state.draftsById, action.user.id),
}
};
}
}
Part 3: Scale
Rule: Keep dependencies low to keep the application fast
Reality: Use bundling to increase PERCEIVED performance
class Routes extends React.Component {
render() {
return (
<Switch>
<Route exact path="/"
component={require(‘../home').default} />
<Route path="/admin"
component={lazy(require(‘bundle-loader?lazy&name=admin!../admin’))} />
<Route component={PageNotFound} />
</Switch>
);
}
}
require('bundle-loader?lazy&name=admin!../admin’)
const lazy = loader => class extends React.Component {
componentWillMount() {
loader(mod =>
this.setState({
Component: mod.default ? mod.default : mod
})
);
}
render() {
const { Component } = this.state;
if (Component !== null) {
return <Component {...this.props} />;
} else {
return <div>Is Loading!</div>;
}
}
};
Rule: Render up-to-date data
Reality: If you got something render it, update it later
Epilog: Scale?
Rule: Scale is bytes served, users concurrent
Reality: Scale is responding to bytes served and users concurrent
How fast can you deploy?
Pre: Clear homebrew & yarn caches
1. Reinstall node & yarn via brew
2. Clone repo
3. Run yarn install
4. Run production build
1. Compile & Minify CSS
2. Compile Server via Babel
3. Compile, Minify, & Gzip via Webpack
190.64s
~3 min
<Feature name="new-feature" fallback={<OldFeatureComponent />}>
<NewFeatureComponent />
</Feature>
Team 1
Team 2
MergeFeatureA
MergeFeatureB
Deploy
Deploy
OMG
ROLLBACK
DEPLOY!!!
MergeFeatureC
MergeBugfixforA
Deploy
DeployBLOCKED!!!
Deploy
Team 1
Team 2
MergeFeatureA
MergeFeatureB
Deploy
Deploy
RolloutFlagARolloutFlagBOMG
ROLLBACK
FLAG
A!!!
MergeFeatureC
Deploy
MergeBugfixforA
Deploy
RolloutFlagA
RolloutFlagC
Can you optimize your directory structure around team responsibilities?
If teams are organized by “product domain”,
Can you organize code around product domain?
Final Thoughts
Strict rules rarely 100% apply to your application.
Remembering the purpose behind the rules is valuable.
Code behavior should be predictable and intuitable.
Be realistic about the problem you’re actually solving.
You will not get it perfect the first time.
Optimize your processes for refactoring.
Questions?
Watch the video with slide synchronization on
InfoQ.com!
https://www.infoq.com/presentations/react-
redux-scale

Contenu connexe

Similaire à React+Redux at Scale

N Things You Don't Want to Repeat in React Native
N Things You Don't Want to Repeat in React NativeN Things You Don't Want to Repeat in React Native
N Things You Don't Want to Repeat in React NativeAnton Kulyk
 
React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practicesClickky
 
Reactивная тяга
Reactивная тягаReactивная тяга
Reactивная тягаVitebsk Miniq
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsEvangelia Mitsopoulou
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgetsvelveeta_512
 
Introduction to React and MobX
Introduction to React and MobXIntroduction to React and MobX
Introduction to React and MobXAnjali Chawla
 
How Reactive do we need to be
How Reactive do we need to beHow Reactive do we need to be
How Reactive do we need to beJana Karceska
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react applicationGreg Bergé
 
Dependency injection - the right way
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right wayThibaud Desodt
 
React Native - Workshop
React Native - WorkshopReact Native - Workshop
React Native - WorkshopFellipe Chagas
 
Functional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwiftFunctional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwiftRodrigo Leite
 
Reactive.architecture.with.Angular
Reactive.architecture.with.AngularReactive.architecture.with.Angular
Reactive.architecture.with.AngularEvan Schultz
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxVisual Engineering
 
Opencast Admin UI - Introduction to developing using AngularJS
Opencast Admin UI - Introduction to developing using AngularJSOpencast Admin UI - Introduction to developing using AngularJS
Opencast Admin UI - Introduction to developing using AngularJSbuttyx
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0Tobias Meixner
 
Connect.js - Exploring React.Native
Connect.js - Exploring React.NativeConnect.js - Exploring React.Native
Connect.js - Exploring React.Nativejoshcjensen
 
Manage the Flux of your Web Application: Let's Redux
Manage the Flux of your Web Application: Let's ReduxManage the Flux of your Web Application: Let's Redux
Manage the Flux of your Web Application: Let's ReduxCommit University
 
Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)
Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)
Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)indeedeng
 

Similaire à React+Redux at Scale (20)

N Things You Don't Want to Repeat in React Native
N Things You Don't Want to Repeat in React NativeN Things You Don't Want to Repeat in React Native
N Things You Don't Want to Repeat in React Native
 
React + Redux. Best practices
React + Redux.  Best practicesReact + Redux.  Best practices
React + Redux. Best practices
 
Reactивная тяга
Reactивная тягаReactивная тяга
Reactивная тяга
 
Battle of React State Managers in frontend applications
Battle of React State Managers in frontend applicationsBattle of React State Managers in frontend applications
Battle of React State Managers in frontend applications
 
Getting the Most Out of jQuery Widgets
Getting the Most Out of jQuery WidgetsGetting the Most Out of jQuery Widgets
Getting the Most Out of jQuery Widgets
 
Introduction to React and MobX
Introduction to React and MobXIntroduction to React and MobX
Introduction to React and MobX
 
How Reactive do we need to be
How Reactive do we need to beHow Reactive do we need to be
How Reactive do we need to be
 
Recompacting your react application
Recompacting your react applicationRecompacting your react application
Recompacting your react application
 
Dependency injection - the right way
Dependency injection - the right wayDependency injection - the right way
Dependency injection - the right way
 
React Native - Workshop
React Native - WorkshopReact Native - Workshop
React Native - Workshop
 
React/Redux
React/ReduxReact/Redux
React/Redux
 
Functional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwiftFunctional Reactive Programming - RxSwift
Functional Reactive Programming - RxSwift
 
Reactive.architecture.with.Angular
Reactive.architecture.with.AngularReactive.architecture.with.Angular
Reactive.architecture.with.Angular
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
 
Opencast Admin UI - Introduction to developing using AngularJS
Opencast Admin UI - Introduction to developing using AngularJSOpencast Admin UI - Introduction to developing using AngularJS
Opencast Admin UI - Introduction to developing using AngularJS
 
GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0GraphQL Bangkok Meetup 2.0
GraphQL Bangkok Meetup 2.0
 
Connect.js - Exploring React.Native
Connect.js - Exploring React.NativeConnect.js - Exploring React.Native
Connect.js - Exploring React.Native
 
Manage the Flux of your Web Application: Let's Redux
Manage the Flux of your Web Application: Let's ReduxManage the Flux of your Web Application: Let's Redux
Manage the Flux of your Web Application: Let's Redux
 
Rails is not just Ruby
Rails is not just RubyRails is not just Ruby
Rails is not just Ruby
 
Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)
Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)
Indeed My Jobs: A case study in ReactJS and Redux (Meetup talk March 2016)
 

Plus de C4Media

Streaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live VideoStreaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live VideoC4Media
 
Next Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy MobileNext Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy MobileC4Media
 
Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020C4Media
 
Understand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java ApplicationsUnderstand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java ApplicationsC4Media
 
Kafka Needs No Keeper
Kafka Needs No KeeperKafka Needs No Keeper
Kafka Needs No KeeperC4Media
 
High Performing Teams Act Like Owners
High Performing Teams Act Like OwnersHigh Performing Teams Act Like Owners
High Performing Teams Act Like OwnersC4Media
 
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to JavaDoes Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to JavaC4Media
 
Service Meshes- The Ultimate Guide
Service Meshes- The Ultimate GuideService Meshes- The Ultimate Guide
Service Meshes- The Ultimate GuideC4Media
 
Shifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDShifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDC4Media
 
CI/CD for Machine Learning
CI/CD for Machine LearningCI/CD for Machine Learning
CI/CD for Machine LearningC4Media
 
Fault Tolerance at Speed
Fault Tolerance at SpeedFault Tolerance at Speed
Fault Tolerance at SpeedC4Media
 
Architectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsArchitectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsC4Media
 
ML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsC4Media
 
Build Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerBuild Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerC4Media
 
User & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleUser & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleC4Media
 
Scaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeScaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeC4Media
 
Make Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereMake Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereC4Media
 
The Talk You've Been Await-ing For
The Talk You've Been Await-ing ForThe Talk You've Been Await-ing For
The Talk You've Been Await-ing ForC4Media
 
Future of Data Engineering
Future of Data EngineeringFuture of Data Engineering
Future of Data EngineeringC4Media
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreC4Media
 

Plus de C4Media (20)

Streaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live VideoStreaming a Million Likes/Second: Real-Time Interactions on Live Video
Streaming a Million Likes/Second: Real-Time Interactions on Live Video
 
Next Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy MobileNext Generation Client APIs in Envoy Mobile
Next Generation Client APIs in Envoy Mobile
 
Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020Software Teams and Teamwork Trends Report Q1 2020
Software Teams and Teamwork Trends Report Q1 2020
 
Understand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java ApplicationsUnderstand the Trade-offs Using Compilers for Java Applications
Understand the Trade-offs Using Compilers for Java Applications
 
Kafka Needs No Keeper
Kafka Needs No KeeperKafka Needs No Keeper
Kafka Needs No Keeper
 
High Performing Teams Act Like Owners
High Performing Teams Act Like OwnersHigh Performing Teams Act Like Owners
High Performing Teams Act Like Owners
 
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to JavaDoes Java Need Inline Types? What Project Valhalla Can Bring to Java
Does Java Need Inline Types? What Project Valhalla Can Bring to Java
 
Service Meshes- The Ultimate Guide
Service Meshes- The Ultimate GuideService Meshes- The Ultimate Guide
Service Meshes- The Ultimate Guide
 
Shifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CDShifting Left with Cloud Native CI/CD
Shifting Left with Cloud Native CI/CD
 
CI/CD for Machine Learning
CI/CD for Machine LearningCI/CD for Machine Learning
CI/CD for Machine Learning
 
Fault Tolerance at Speed
Fault Tolerance at SpeedFault Tolerance at Speed
Fault Tolerance at Speed
 
Architectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep SystemsArchitectures That Scale Deep - Regaining Control in Deep Systems
Architectures That Scale Deep - Regaining Control in Deep Systems
 
ML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.jsML in the Browser: Interactive Experiences with Tensorflow.js
ML in the Browser: Interactive Experiences with Tensorflow.js
 
Build Your Own WebAssembly Compiler
Build Your Own WebAssembly CompilerBuild Your Own WebAssembly Compiler
Build Your Own WebAssembly Compiler
 
User & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix ScaleUser & Device Identity for Microservices @ Netflix Scale
User & Device Identity for Microservices @ Netflix Scale
 
Scaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's EdgeScaling Patterns for Netflix's Edge
Scaling Patterns for Netflix's Edge
 
Make Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home EverywhereMake Your Electron App Feel at Home Everywhere
Make Your Electron App Feel at Home Everywhere
 
The Talk You've Been Await-ing For
The Talk You've Been Await-ing ForThe Talk You've Been Await-ing For
The Talk You've Been Await-ing For
 
Future of Data Engineering
Future of Data EngineeringFuture of Data Engineering
Future of Data Engineering
 
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and MoreAutomated Testing for Terraform, Docker, Packer, Kubernetes, and More
Automated Testing for Terraform, Docker, Packer, Kubernetes, and More
 

Dernier

Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sectoritnewsafrica
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentMahmoud Rabie
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Jeffrey Haguewood
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
Kuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialKuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialJoão Esperancinha
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesManik S Magar
 
Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#Karmanjay Verma
 
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Mark Simos
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesThousandEyes
 
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...amber724300
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfAarwolf Industries LLC
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentPim van der Noll
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Alkin Tezuysal
 

Dernier (20)

Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
4. Cobus Valentine- Cybersecurity Threats and Solutions for the Public Sector
 
Digital Tools & AI in Career Development
Digital Tools & AI in Career DevelopmentDigital Tools & AI in Career Development
Digital Tools & AI in Career Development
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
Email Marketing Automation for Bonterra Impact Management (fka Social Solutio...
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
Kuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorialKuma Meshes Part I - The basics - A tutorial
Kuma Meshes Part I - The basics - A tutorial
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
 
Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#Microservices, Docker deploy and Microservices source code in C#
Microservices, Docker deploy and Microservices source code in C#
 
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
Tampa BSides - The No BS SOC (slides from April 6, 2024 talk)
 
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyesAssure Ecommerce and Retail Operations Uptime with ThousandEyes
Assure Ecommerce and Retail Operations Uptime with ThousandEyes
 
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
JET Technology Labs White Paper for Virtualized Security and Encryption Techn...
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Landscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdfLandscape Catalogue 2024 Australia-1.pdf
Landscape Catalogue 2024 Australia-1.pdf
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native developmentEmixa Mendix Meetup 11 April 2024 about Mendix Native development
Emixa Mendix Meetup 11 April 2024 about Mendix Native development
 
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
Unleashing Real-time Insights with ClickHouse_ Navigating the Landscape in 20...
 

React+Redux at Scale

  • 2. InfoQ.com: News & Community Site • 750,000 unique visitors/month • Published in 4 languages (English, Chinese, Japanese and Brazilian Portuguese) • Post content from our QCon conferences • News 15-20 / week • Articles 3-4 / week • Presentations (videos) 12-15 / week • Interviews 2-3 / week • Books 1 / month Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/ react-redux-scale
  • 3. Presented at QCon New York www.qconnewyork.com Purpose of QCon - to empower software development by facilitating the spread of knowledge and innovation Strategy - practitioner-driven conference designed for YOU: influencers of change and innovation in your teams - speakers and topics driving the evolution and innovation - connecting and catalyzing the influencers and innovators Highlights - attended by more than 12,000 delegates since 2007 - held in 9 cities worldwide
  • 5.
  • 6.
  • 7.
  • 8.
  • 10.
  • 12.
  • 13.
  • 14. Scalability is the capability of a system, network, or process to handle a growing amount of work, or its potential to be enlarged to accommodate that growth. – Wikipedia
  • 16. Rule: Components should be stateless
  • 17. Reality: State is the enemy, but also inevitable
  • 18. onClick(e) { const value = e.target.value; const formatted = value.toUpperCase(); this.setState({value: formatted}); }
  • 19. onClick() { this.setState((previousState, currentProps) => { return { show: !previousState.show, }; }); }
  • 21. onClick(e) { this.setState({value: e.target.value}, () => { this.props.onChange(this.state.value); }); }
  • 22. Rule: Don’t use Context, it hides complexity
  • 23. Reality: Sometimes complexity should be hidden
  • 24.
  • 25.
  • 26. class TextCard extends React.Component { static contextTypes = { metatypes: React.PropTypes.object, }; render() { const {cardData} = this.props; const {metatypes} = this.context; return ( <div> The following is either editable or displayed: <metatypes.text value={cardData.text} onChange={this.props.onChange} /> </div> ) } } function selectCardComponent(cardData) { switch (cardData.type) { case 'text': return TextCard; default: throw new Error(`Invalid card type ${cardData.type}`); } }
  • 27. class TextCard extends React.Component { static contextTypes = { metatypes: React.PropTypes.object, }; render() { const {cardData} = this.props; const {metatypes} = this.context; return ( <div> The following is either editable or displayed: <metatypes.text value={cardData.text} onChange={this.props.onChange} /> </div> ) } } function selectCardComponent(cardData) { switch (cardData.type) { case 'text': return TextCard; default: throw new Error(`Invalid card type ${cardData.type}`); } }
  • 28. const metatypesEdit = { text: class extends React.Component { render() { return <input type="text" {...this.props} />; } } } const metatypesView = { text: class extends React.Component { render() { return <span>{this.props.value}</span>; } } }
  • 29. class CardViewer extends React.Component { static childContextTypes = { metatypes: React.PropTypes.object }; getChildContext() { return {metatypes: metatypesView}; } render() { const {cardData} = this.props; const CardComponent = selectCardComponent(cardData); return <CardComponent cardData={cardData} /> } }
  • 30. class CardEditor extends React.Component { static childContextTypes = { metatypes: React.PropTypes.object }; getChildContext() { return {metatypes: metatypesEdit}; } render() { const {cardData} = this.props; const CardComponent = selectCardComponent(cardData); return <CardComponent cardData={cardData} /> } }
  • 32. Rule: “Single source of truth” means all state in the store
  • 33. Reality: You can have multiple “single sources”
  • 35. this.props.checked = true; this.props.checked = true; this.props.checked = true; this.state.checked = true;
  • 36. this.props.checked = true; this.props.checked = true; this.props.checked = true; this.props.checked = true; checked: true connect()();
  • 38. Rule: Side effects should happen outside the Redux cycle
  • 39. Reality: This doesn’t mean you can’t have callbacks
  • 40. function persistPostAction(post, callback = () => {}) { return { type: 'PERSIST_POST', post, callback }; } function *fetchPostsSaga(action) { const status = yield putPostAPI(action.post); yield put(persistPostCompleteAction(status)); yield call(action.callback, status); } class ComposePost extends React.Component { onClickSubmit() { const {dispatch} = this.props; const {post} = this.state; dispatch(persistPostAction(post, () => this.displaySuccessBanner())); } }
  • 41. class ViewPostPage extends React.Component { componentWillMount() { const {dispatch, postId} = this.props; dispatch(fetchPostAction(postId, () => this.logPageLoadComplete())); } }
  • 42. Rule: Redux stores must be normalized for performance
  • 43. Reality: You must normalize to reduce complexity
  • 46. { byId: { 'a': userA, 'b': userB, 'c': userC, 'd': userD }, keyWindows: ['browseUsers', 'allManagers'], browseUsers: { ids: ['a', 'b', 'c'], isFetching: false, page: 1, totalPages: 10, next: '/users?page=2', last: '/users?page=10' }, allManagers: { ids: ['d', 'a'], isFetching: false } }
  • 47. function selectUserById(store, userId) { return store.users.byId[userId]; } function selectUsersByKeyWindow(store, keyWindow) { return store.users[keyWindow].ids.map(userId => selectUserById(store, userId)); }
  • 48. function fetchUsers({query}, keyWindow) { return { type: FETCH_USERS, query, keyWindow }; } function fetchManagers() { return fetchUsers({query: {isManager: true}}, 'allManager'); } function receiveEntities(entities, keyWindow) { return { type: RECEIVE_ENTITIES, entities, keyWindow }; }
  • 49. function reducer(state = defaultState, action) { switch(action.type) { case FETCH_USERS: return { ...state, keyWindows: uniq([...state.keyWindows, action.keyWindow]), [action.keyWindow]: { ...state[action.keyWindow], isFetching: true, query: action.query } }; case RECEIVE_ENTITIES: return { ...state, byId: { ...state.byId, ...action.entities.users.byId }, keyWindows: uniq([...state.keyWindows, action.keyWindow]), [action.keyWindow]: { ...state[action.keyWindow], isFetching: false, ids: action.entities.users.ids } }; } }
  • 50. function reducer(state = defaultState, action) { switch(action.type) { case FETCH_USERS: return { ...state, keyWindows: uniq([...state.keyWindows, action.keyWindow]), [action.keyWindow]: { ...state[action.keyWindow], isFetching: true, query: action.query } }; case RECEIVE_ENTITIES: return { ...state, byId: { ...state.byId, ...action.entities.users.byId }, keyWindows: uniq([...state.keyWindows, action.keyWindow]), [action.keyWindow]: { ...state[action.keyWindow], isFetching: false, ids: action.entities.users.ids } }; } }
  • 51. function selectUsersAreFetching(store, keyWindow) { return !!store.users[keyWindow].isFetching; } function selectManagersAreFetching(store) { return selectUsersAreFetching(store, 'allManagers'); }
  • 52. function reducer(state = defaultState, action) { switch(action.type) { case UPDATE_USER: return { ...state, draftsById: { ...state.draftsById, [action.user.id]: action.user } }; case RECEIVE_ENTITIES: return { ...state, byId: { ...state.byId, ...action.entities.users.byId }, draftsById: { ...omit(state.draftsById, action.entities.users.byId) }, keyWindows: uniq([...state.keyWindows, action.keyWindow]), [action.keyWindow]: { ...state[action.keyWindow], isFetching: false, ids: action.entities.users.ids } }; } }
  • 53. function reducer(state = defaultState, action) { switch(action.type) { case UPDATE_USER: return { ...state, draftsById: { ...state.draftsById, [action.user.id]: action.user } }; case RECEIVE_ENTITIES: return { ...state, byId: { ...state.byId, ...action.entities.users.byId }, draftsById: { ...omit(state.draftsById, action.entities.users.byId) }, keyWindows: uniq([...state.keyWindows, action.keyWindow]), [action.keyWindow]: { ...state[action.keyWindow], isFetching: false, ids: action.entities.users.ids } }; } }
  • 54. function selectUserById(store, userId) { return store.users.draftsById[userId] || store.users.byId[userId]; }
  • 55. function reducer(state = defaultState, action) { switch(action.type) { case UNDO_UPDATE_USER: return { ...state, draftsById: { ...omit(state.draftsById, action.user.id), } }; } }
  • 57. Rule: Keep dependencies low to keep the application fast
  • 58. Reality: Use bundling to increase PERCEIVED performance
  • 59. class Routes extends React.Component { render() { return ( <Switch> <Route exact path="/" component={require(‘../home').default} /> <Route path="/admin" component={lazy(require(‘bundle-loader?lazy&name=admin!../admin’))} /> <Route component={PageNotFound} /> </Switch> ); } }
  • 61. const lazy = loader => class extends React.Component { componentWillMount() { loader(mod => this.setState({ Component: mod.default ? mod.default : mod }) ); } render() { const { Component } = this.state; if (Component !== null) { return <Component {...this.props} />; } else { return <div>Is Loading!</div>; } } };
  • 62.
  • 64. Reality: If you got something render it, update it later
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 72. Rule: Scale is bytes served, users concurrent
  • 73. Reality: Scale is responding to bytes served and users concurrent
  • 74. How fast can you deploy?
  • 75.
  • 76. Pre: Clear homebrew & yarn caches 1. Reinstall node & yarn via brew 2. Clone repo 3. Run yarn install 4. Run production build 1. Compile & Minify CSS 2. Compile Server via Babel 3. Compile, Minify, & Gzip via Webpack 190.64s ~3 min
  • 77. <Feature name="new-feature" fallback={<OldFeatureComponent />}> <NewFeatureComponent /> </Feature>
  • 78.
  • 81. Can you optimize your directory structure around team responsibilities? If teams are organized by “product domain”, Can you organize code around product domain?
  • 83. Strict rules rarely 100% apply to your application. Remembering the purpose behind the rules is valuable.
  • 84. Code behavior should be predictable and intuitable. Be realistic about the problem you’re actually solving.
  • 85. You will not get it perfect the first time. Optimize your processes for refactoring.
  • 87. Watch the video with slide synchronization on InfoQ.com! https://www.infoq.com/presentations/react- redux-scale