Successfully reported this slideshow.

Arquitetura JavaScript Escalável da Netflix

6

Share

Upcoming SlideShare
Introdução ext js 4
Introdução ext js 4
Loading in …3
×
1 of 65
1 of 65

Arquitetura JavaScript Escalável da Netflix

6

Share

Download to read offline

E se ao invés de usar classes, instâncias, camadas e MVC nós voltarmos aos fundamentos do JavaScript e construir aplicações inteiras somente com funções?

Slides da palestra sobre a arquitetura da Netflix, demonstrando como nós usamos Componentes Funcionais e React para construir nossas aplicações.

Apresentada no TDC Porto Alegre 2016.

Vídeo e mais informações em http://bruno.tavares.me

E se ao invés de usar classes, instâncias, camadas e MVC nós voltarmos aos fundamentos do JavaScript e construir aplicações inteiras somente com funções?

Slides da palestra sobre a arquitetura da Netflix, demonstrando como nós usamos Componentes Funcionais e React para construir nossas aplicações.

Apresentada no TDC Porto Alegre 2016.

Vídeo e mais informações em http://bruno.tavares.me

More Related Content

Related Books

Free with a 14 day trial from Scribd

See all

Arquitetura JavaScript Escalável da Netflix

  1. 1. Arquitetura Escalável da Netflix Bruno Tavares @bt_bruno
  2. 2. Mas antes…
  3. 3. 3 curiosidades sobre a que você não sabia.
  4. 4. #1
  5. 5. roda em de dispositivos MILHARES
  6. 6. Também!
  7. 7. #2
  8. 8. Nós temos uma super secreta plataforma para TV.
  9. 9. Codinome Gibbon
  10. 10. Netflix TV Netflix TV Platform 2010100% HTML, CSS, JS Empacotada para TV
  11. 11. Performance? $30 600mhz single core JavaScript Core sem JIT 465x mais lento que V8 no seu laptop.
  12. 12. Netflix TV Platform Webkit JavaScript Core Netflix TV UI (JS, HTML, CSS) DOM DOM Rendering Device Interface 2012 Gibbon JavaScript Core Netflix TV UI (JS only) Widget Object Model Widget Rendering Device Interface 2013
  13. 13. Webkit <div style=” background-color:#2C425C; width:200px; height:200px; color:#FFFFF"> Hello World </div> Hello World gibbon.createWidget({ backgroundColor: "#2C425C", width: 200, height: 200, color: "#FFFFFF", text: "Hello World" }); Gibbon Hello World
  14. 14. #3
  15. 15. Nós lançamos tudo com Testes A/B
  16. 16. Testes A/B
  17. 17. Testes A/B ✓
  18. 18. Testes A/B ✓
  19. 19. Controle Sem sinopse nem play Sem sinopse Sem play
  20. 20. Arquitetura altamente escalável Mais velocidade e volume de testes A/B Mais inovação e vantagem competitiva
  21. 21. Arquitetura Anterior View Controller Model
  22. 22. Quebrando MVC View Controller Model ViewViewView ControllerControllerController ModelModelModelModel View
  23. 23. Será que entendemos JavaScript errado?
  24. 24. Estado mutável e compartilhado é a raiz de todos os males.
  25. 25. Objetos e Camadas Componentes Funcionais
  26. 26. JavaScript Funcional λ
  27. 27. Código expresso de forma declarativa, em pequenas funções, evitando alteração de estado e dados mutáveis.
  28. 28. 4 princípios da nossa arquitetura
  29. 29. #1 Componentes Puros
  30. 30. Funções Puras function formatTitle(title) { return `<h1>${title}</h1>`; } Entrada Saída Para os mesmos parâmetros, sempre o mesmo resultado // ... formatTitle('Narcos'); // <h1>Narcos</h1>
  31. 31. Componente Dados View Componentes Puros
  32. 32. const Boxshot = React.createClass({ render() { return <img src={this.props.src} /> } }); Componentes Puros - React const view = Boxshot({ src: '…' });
  33. 33. const Boxshot = React.createClass({ render() { return <img src={this.props.src} /> } }); Componentes Puros - React const view = Boxshot({ src: '…' }); Entrada const Boxshot = function(props) { return <img src={props.src} /> } const Boxshot = (props) => ( <img src={props.src} /> ); Saída
  34. 34. Previsíveis Independente de Estado Fácil de refatorar Composição
  35. 35. #2 API Declarativa
  36. 36. // imperativo Boxshot(data.movie); //<img … /> // declarativo <Boxshot movie={data.movie} />
  37. 37. // imperativo var panel = $('#panel'); if (isPanelVisible) { panel.show(); } else { panel.hide(); } // declarativo <Panel visible={isPanelVisible} />
  38. 38. // declarativo const app = ( <Gallery> <Category category={netflixOriginals}> <Boxshot movie={narcos} /> <Boxshot movie={strangerThings} /> <Boxshot movie={lukeCage} /> </Category> </Gallery> ); render(app);
  39. 39. Legibilidade Melhor compreensão Menos margem para bugs
  40. 40. #3 Composição
  41. 41. App Componente Componente Componente Componente Dados View
  42. 42. Boxshot Focusable RemoteData
  43. 43. // boxshot component const Boxshot = (props) => ( <img src={props.src} /> ); // inject focus capability const BoxshotWithFocus = Focusable(Boxshot); // inject remote data fetching const BoxshotWithData = RemoteData(BoxshotWithFocus);
  44. 44. Escalabilidade Complexidade Controlada API Estável
  45. 45. #4 Fluxo Unidirecional
  46. 46. Dados { … } HTML < … > Componentes Puros HTML < … >
  47. 47. Dados { … } HTML < … > Componentes Puros Dados { … } HTML < … >
  48. 48. Dados { … } Componentes Puros HTML < … > HTML < … >
  49. 49. Bacana… e como eu executo efeitos colaterais?
  50. 50. Dados { … } HTML < … > AçãoRedutor
  51. 51. // state { selectedMovie: 80025313 }
  52. 52. // fire action this.props.selectMovieAction({ movie: 20057281 });
  53. 53. // reducer changes state newState = state.set( 'selectedMovie', action.movie );
  54. 54. // state { selectedMovie: 80025313 } // state { selectedMovie: 20057281} Ação Redutor
  55. 55. E se você pudesse criar toda sua aplicação, só com componentes puros?
  56. 56. { categories: [{ title: 'Top Picks for You', movies: [{ title: 'Narcos', boxshot: 'http:.../narcos.jpg' }, ... ] }, ...] }
  57. 57. const Boxshot = (props) => ( <img src={props.movie.boxshot} /> );
  58. 58. const Boxshot = (props) => ( <img src={props.movie.boxshot} /> ); const Category = (props) => ( <div> <h2>{props.category.title}</h2> </div> ); {props.category.movies.map(movie, i) => ( <Boxshot movie={movie} /> ))}
  59. 59. const Boxshot = (props) => ( <img src={props.movie.boxshot} /> ); const Category = (props) => ( <div> <h2>{props.category.title}</h2> </div> ); const Gallery = (props) => ( <div> </div> ); {props.category.movies.map(movie, i) => ( <Boxshot movie={movie} /> ))} {props.categories.map(category => ( <Category category={category} /> ))}
  60. 60. Previsível Declarativa Extensível Unidirecional Imutável Arquitetura Escalável
  61. 61. app = (dados) => view
  62. 62. Obrigado! Bruno Tavares @bt_bruno

Editor's Notes

  • O objetivo dessa apresentação é compartilhar como nós usamos programação funcional e componentes React para construir uma arquitetura escalável.
  • Mas antes…
  • 3 curiosidades sobre a Netflix que você não sabia!
  • #1
  • Nós amamos JavaScript!
  • Netflix roda em milhares de dispositivos…
  • …JavaScript também! Nós temos essa linguagem tão versátil que nos permite pular de plataforma para plataforma com o mínimo de fricção.
  • #2
  • Nós temos uma super secreta plataforma para TV.
  • Ela se chama Gibbon, e é uma camada nativa controlada por código JavaScript.
  • Nossa aplicação antiga era toda baseada em HTML, CSS e JS. Ela rodava até em navegadores Webkit, mas nós empacotávamos tudo para as televisões.
  • Porém nós temos uns dispositivos um tanto quanto desafiadores. Esses streaming sticks, por exemplo, custam apenas $30, tem um processador single core de 600mhz, JavaScript Core sem just-in-time compilation, e é 465x mais lento que o V8 no meu laptop.
  • Então nós paramos de usar webkit, e criamos uma plataforma própria que se assemelha muito, porém toda arquitetada para performance e que ainda suportasse uma UI em JavaScript.
  • O código parece muito similar, porém o código HTML é totalmente declarativo, enquanto no Gibbon nós usamos chamadas imperativas no JavaScript.
  • #3
  • Nós lançamos tudo com testes A/B.
  • Nós testamos experiências novas em uma parcela dos nossos usuários.
  • Caso a nova experiência demonstre métricas positivas…
  • …nós lançamos em produção para todos usuários.
  • E nos fazemos isso tanto para mudanças grandes, como também para pequenas optimizações. Então imagine a quantidade de alterações que cada componente pode receber, e quantas permutações a nossa interface precisa suportar.
  • As decisões que nossa equipe toma com relação à arquitetura estão diretamente relacionadas à velocidade e volume de testes A/B, que por sua vez impactam a nossa abilidade de inovar. Isso reforça o valor de ter uma boa arquitetura desde o começo, porque essa decisão afeta em muito o nosso produto.
  • Entrando mais na parte técnica, a nossa arquitetura anterior funcionava com o bom e velho MVC. O controller recebe eventos da view, altera o model, que por sua vez dispara um evento, a view escuta e se atualiza, e tudo funciona muito bem.
  • Porém 6 anos e centenas de testes A/B depois, a nossa arquitetura se parece mais com isso.

    A medida que a aplicação foi crescendo, muitos canais secundários foram criando-se e ficou muito difícil compreender o fluxo do código, das dependências, e mais importante, das mutações do estado da aplicação.
  • Nesse ponto começamos a nos perguntar se estávamos entendedo JavaScript errado.

    Viemos do mundo dos servidores aonde a requisição começa, executa e termina. Uma nova requisição começa tudo do zero, e a probabilidade de entrar em um mal estado é muito menor.

    Porém no front-end o nosso usuário pode sentar no sofá na sexta e só parar a maratona de Narcos no domingo! Quem consegue prever o estado da aplicação 3 dias depois de inicializada?
  • Então nós chegamos a conclusão que estado mutável e compartilhado é a raiz de todos os males. Com tantos canais secundários na nossa arquitetura MVC, era impossível acompanhar o fluxo de alterações.

    Partes da nossa aplicação tinha o ”expert” dedicado, que era a pessoa que entendia daquela área e estava melhor qualificada para realizar alterações, já que ela compreendia melhor os diferentes estados. Isso era altamente indesejável e engessava nossa abilidade de inovar.
  • Então nós começamos experimentos, saindo de uma arquitetura onde tudo eram objetos e camadas, e começamos a construir nosso código como um fluxo de componentes funcionais.
  • Nós começamos a utilizar mais conceitos de JavaScript Funcional ao invés de Orientação à Objetos.
  • Em sua definição, o paradigma de programação funcional dita que o código seja expresso de forma declarativa, em pequenas funções, evitando alteração de estado e dados mutáveis.

    Só nessa pequena definição nós encontramos uma série de palavras-chave altamente desejáveis para nossa nova arquitetura.
  • Então a partir dos nossos experimentos nós definimos 4 princípios para a nossa arquitetura.
  • #1 Componentes Puros
  • Funções puras são um dos alicerces da programação funcional. Elas são excelentes por serem previsíveis, idependende de qualquer estado exterior - e portanto imune à muitos erros introduzidos por estados compartilhados – e fáceis de refatorar, reorganizar, mover, e compôr.
  • Se nós conseguissemos aplicar o mesmo para componentes, e criar componentes puros, nós poderíamos extrair as mesmas qualidades da função pura.
  • Para isso nós usamos React. Ele é um framework que nos permite aplicar conceitos de programação funcional e construir interfaces inteiras somente com funções.Esse é um pequeno exemplo de um componente puro. Ele não tem estado nenhum, somente renderiza os valores passados por `props`. Para consumir, nós podemos invocar ele como qualquer outra função.
  • Ele é tão mesmo uma função, que o React nos permite reescrevê-lo dessa forma. Se você analizar, é o mesmo conceito da função pura, aonde nós temos uma entrada, uma saída, e nenhum estado. Dessa forma nós conseguimos ter um componente puro, e usá-lo como alicerce da nossa arquitetura.
  • Componentes puros garantem previsibilidade, já que para as mesmas entradas, sempre terão a mesma saída. Eles são independentes de estado, fáceis de refatorar e podem ser compostos em componentes cada vez mais complexos.
  • #2 API Declarativa
  • API Declarativas nos proporcionam código mais conciso, legível e de fácil compreensão.
  • Ao invés de dizer exatamente como fazer, nós apenas expressamos o que queremos fazer.
  • Definir hierarquias também é muito melhor na forma declarativa, do que um código imperativo que levaria dezenas de linhas de código.
  • No final das contas, ela é uma forma mais legível, de fácil compreensão e com menos margem para bugs.
  • #3 Composição
  • Nosso objetivo não é só ficar em componentes pequenos, mas compôr eles de modo a criar a aplicação inteira de forma pura e funcional, onde dados entram no topo e a aplicação completa sai como retorno.
  • Nós podemos também extender um componentes com mais funcionalidades usando composição ao invés de criar classes e extendê-las (herança).
  • Composição nos proporciona escalabilidade. Também nos permite criar interfaces complexas de forma controlada. Alterações em um componente base não afetam àqueles que o extendem, já que eles usam composição e não herança.
  • #4 Fluxo Unidirecional
  • React nos permite voltar à maneira de trabalhar que usávamos nos velhos tempos de aplicações PHP.
  • Quando os dados mudam…
  • Nós jogamos tudo fora e renderizamos de novo.
  • Bacana… e como eu executo efeitos colaterais?
  • Nós usamos ações e redutores. Quando algum efeito colateral (uma troca de rota, uma requisição, um evento de teclado, etc…) acontece, uma ação é disparada para representar aquele efeito. O redutor então verifica se para aquela ação é preciso alterar o estado. Se for preciso, ele vai alterar o estado – que é imutável – e receberá o novo estado. O novo estado é então passado para os componentes puros que criar a nova interface.
  • E se você pudesse criar toda sua aplicação, só com componentes puros?
  • Essa é a galeria do Netflix. Nós temos o componente Gallery. Cada linha é um componente Category. Cada filme é um componente Boxshot.
  • A nossa estrutura de dados parece-se com isso.
  • Nosso primeiro componente puro Boxshot recebe as props e retorna a nova view.
  • Nosso componente categoria faz o mesmo. Ele também mapeia todos os filmes para componentes Boxshot.
  • E a galeria faz o mesmo, mapeando categorias para o componente Category.
  • No fim nós temos nossa interface inteira, somente com componentes puros!
  • E com isso nós finalizamos a base da arquitetura da Netflix. Ela é previsível, declarativa, extensível, unidirecional e imutável.
  • Ela nos permite fazer essa expressão uma realidade, aonde o nosso aplicativo é um produto dos dados, passado à uma função que retorna toda a view.
  • Obrigado! Bruno Tavares (@bt_bruno)
  • ×