O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

Desafios do Desenvolvimento de Front-end em um e-commerce

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Carregando em…3
×

Confira estes a seguir

1 de 161 Anúncio

Desafios do Desenvolvimento de Front-end em um e-commerce

Baixar para ler offline

Quando o objetivo é vender, uma modificação mínima pode impactar a taxa de conversão final. Para que um e-commerce atinja sua performance máxima, é necessário fazer com que os componentes, a equipe e mínimos detalhes funcionem em perfeita harmonia -- e o front-end é um deles.

Nesta palestra, mostrei os desafios enfrentados pelo time de engenharia de Front-end da Baby.com.br: como trabalhar com uma equipe com vários desenvolvedores, gerando componentes auto-contidos, testáveis e escaláveis, mantendo a melhor performance possível, sem perder o padrão de qualidade.

Fonte das métricas: http://blog.bizelo.com/blog/2012/10/18/infographic-shopping-cart-abandonment-rates/

Quando o objetivo é vender, uma modificação mínima pode impactar a taxa de conversão final. Para que um e-commerce atinja sua performance máxima, é necessário fazer com que os componentes, a equipe e mínimos detalhes funcionem em perfeita harmonia -- e o front-end é um deles.

Nesta palestra, mostrei os desafios enfrentados pelo time de engenharia de Front-end da Baby.com.br: como trabalhar com uma equipe com vários desenvolvedores, gerando componentes auto-contidos, testáveis e escaláveis, mantendo a melhor performance possível, sem perder o padrão de qualidade.

Fonte das métricas: http://blog.bizelo.com/blog/2012/10/18/infographic-shopping-cart-abandonment-rates/

Anúncio
Anúncio

Mais Conteúdo rRelacionado

Diapositivos para si (14)

Semelhante a Desafios do Desenvolvimento de Front-end em um e-commerce (20)

Anúncio

Mais de Eduardo Shiota Yasuda (13)

Mais recentes (20)

Anúncio

Desafios do Desenvolvimento de Front-end em um e-commerce

  1. 1. os desafios do desenvolvimento de front-end em um e-commerce @shiota 2013
  2. 2. olá!slideshare.net/eshiota github.com/eshiota @shiota
  3. 3. front-end engineer @
  4. 4. DEV
  5. 5. e-commerce 101 em alguns slides
  6. 6. =)
  7. 7. taxa de conversão dos usuários que entram no site, quantos finalizam uma compra?
  8. 8. ticket médio em média, quanto os usuários gastam por compra?
  9. 9. =) taxa de conversão × ticket médio =
  10. 10. taxa de conversão × ticket médio = $
  11. 11. = $=)
  12. 12. = ?=)
  13. 13. complexo indeciso exigente inexperiente decidido cuidadoso experiente
  14. 14. ser humano, como todos nós =)
  15. 15. o que faz o usuário abandonar o carrinho?
  16. 16. alto custo de frete $
  17. 17. não estão prontos para finalizar ?
  18. 18. produtos muito caros $
  19. 19. guardam para depois
  20. 20. não mencionou claramente o frete ?
  21. 21. sem guest checkout
  22. 22. formulário com muitas informações
  23. 23. checkout complexo
  24. 24. website lento
  25. 25. taxas extras
  26. 26. falta de opções de pagamento
  27. 27. entrega demorada
  28. 28. spam de ofertas
  29. 29. site não funciona =(
  30. 30. como o front-end pode melhorar a conversão?
  31. 31. formulário com muitas informações checkout complexo website lento site não funciona
  32. 32. velocidade da página interface estável detalhes = emotion design validação de novas hipóteses
  33. 33. desafios de front-end (agora a palestra começa =P)
  34. 34. múltiplos desenvolvedores desenvolvimento escalável performance client-side testes a/b
  35. 35. trabalhando com vários desenvolvedores
  36. 36. trabalhar em equipe é difícil... =(
  37. 37. aspas simples × aspas duplas
  38. 38. ponto e vírgula no JS × sem ponto e vírgula
  39. 39. JavaScript × CoffeeScript
  40. 40. (JavaScript, claro)
  41. 41. (com ponto e vírgula)
  42. 42. ... mas cada um pode ter uma visão diferente e complementar. =)
  43. 43. code smell performance sintaxe arquitetura
  44. 44. mantenha um code standard para o time.
  45. 45. consistência, legibilidade, sem bikeshed.
  46. 46. git + pull requests
  47. 47. qualquer um revisa, qualquer um comenta.
  48. 48. diferentes visões, mais erros detectados.
  49. 49. o conhecimento é disseminado pelo time.
  50. 50. todos ficam mais criteriosos com o que fazem.
  51. 51. desenvolvimento escalável e testável
  52. 52. desenvolvimento ágil: mudanças precisas, altos ganhos.
  53. 53. melhorias são constantes, e nada é 100% definitivo.
  54. 54. o código deve ser facilmente alterável/adaptável.
  55. 55. dica 1 usem pre-processors de CSS. sério. agora. já. eu espero.
  56. 56. sass +
  57. 57. variáveis, mixins e funções
  58. 58. /********************************************************************* * * Variables Module * * All constants that will be used through the styles must be * defined here. * *********************************************************************/ $TEXT_COLOR : #555; $DISCOUNT_COLOR : #ef6565; $LIGHT_COLOR : #fefafa; $SELECTION_BACKGROUND : #41bdce; $SELECTION_COLOR : #fff; $LINK_COLOR : #447f87; $LINK_HOVER_COLOR : #41bdce; $LINK_ACTIVE_COLOR : #447f87; $ERROR_BACKGROUND : #fffaad; $LIGHT_BACKGROUND : #fefefa; $SITE_WIDTH : 978px; $FOOTER_HEIGHT : 777px; $PURPLE : #905194; $ORANGE : #fbb100;
  59. 59. /********************************************************************* * * Mixins Module * * All general purpose mixins are defined here. * *********************************************************************/ /********************************************************************* * =Clearfix *********************************************************************/ @mixin clearfix { &:after { clear: both; content: " "; display: block; font-size: 0; height: 0; visibility: hidden; } zoom: 1; } /********************************************************************* * =Image replacement * * `display` property should be declare on the element, not here * on the mixin. Element must have fixed width and height. *********************************************************************/ @mixin img_replacement { text-indent: 100%; overflow: hidden; white-space: nowrap; }
  60. 60. /********************************************************************* * * Functions Module * * Custom functions used by the application * *********************************************************************/ // Returns unitless number @function remove-unit($number) { $unit: unit($number); $one: 1; @if $unit == "px" { $one: 1px; } @if $unit == "em" { $one: 1em; } @if $unit == "%" { $one: 1%; } @return $number / $one; } // Returns flexible value // Returns `em` by default, accepts `%` as format. @function flex($target, $context: 14, $unit: "em") { $size: remove-unit($target) / remove-unit($context); @if $unit == "em" { @return #{$size}em; } @if $unit == "%" { @return percentage($size); } } // Alias to `flex` function, using `%` as format. @function perc($target, $context) { @return flex($target, $context, "%"); } // Alias to `flex` function, using `em` as format. @function em($target, $context: 14) { @return flex($target, $context, "em"); }
  61. 61. estilos modularizados em partials
  62. 62. app/ assets/ stylesheets/ base/ _functions.scss _mixins.scss _variables.scss ui/ _breadcrumb.scss _carousel.scss _dentedBox.scss _flashMessage.scss
  63. 63. /******************************************************************************* * * UI > Breadcrumb * * General styles for the breadcrumb. * *******************************************************************************/ .breadcrumb { font-size: em(12px); line-height: em(21px, 12px); text-transform: uppercase; color: #444; width: 978px; } .breadcrumb a, .breadcrumb a:visited, .breadcrumb a:active { color: #444; text-decoration: none; } .breadcrumb a:hover { color: #444; text-decoration: underline; } .breadcrumb .separator { padding: 0 3px; }
  64. 64. /******************************************************************************* * * UI > Loader * * Animated loader for AJAX requests * *******************************************************************************/ @mixin loader_sprite_position($xoffset, $yoffset) { background-position: sprite-position($icon-sprite, loader_sprite, $xoffset, $yoffset); } .loader { width: 25px; height: 25px; display: none; } .loader b { display: block; width: 25px; height: 25px; background-image: sprite-url($icon-sprite); } .loader b, .loader .f1 { @include loader_sprite_position(-10px, -10px); } .loader .f2 { @include loader_sprite_position(-45px, -10px); } .loader .f3 { @include loader_sprite_position(-80px, -10px); } .loader .f4 { @include loader_sprite_position(-115px, -10px); } .loader .f5 { @include loader_sprite_position(-150px, -10px); } .loader .f6 { @include loader_sprite_position(-185px, -10px); } .loader .f7 { @include loader_sprite_position(-220px, -10px); } .loader .f8 { @include loader_sprite_position(-255px, -10px); }
  65. 65. geração automática de sprites acelera o desenvolvimento.
  66. 66. $icon-sprite: sprite-map("icon/*.png", $spacing: 16px, $repeat: no-repeat, $layout: vertical);
  67. 67. $icon-sprite: sprite-map("icon/*.png", $spacing: 16px, $repeat: no-repeat, $layout: vertical);
  68. 68. /* Compass sprite function receives the map variable and image as arguments */ background: sprite($icon-sprite, arrow_dropdown) no-repeat; /* Compiled CSS */ background: url(/assets/icon-s5dab8c2901.png) -40px -158px no-repeat;
  69. 69. função de inline image economiza requests.
  70. 70. /* Compiled CSS */ background: #f5f3fb url('data:image/ png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAMAAAAcVM5PAAAAGXRFWHRTb2Z0d2FyZQBBZG9 iZSBJbWFnZVJlYWR5ccllPAAAAAlQTFRF5+TW////////4qZUpQAAAAN0Uk5T// 8A18oNQQAAACBJREFUeNpiYGBgAgMGBkYog4mJXAbILAiDkVxzAAIMAEMOAPMId2OWAAAAAElFTkSuQmCC ') repeat; /* Generates a base64 image */ background: #f5f3eb inline-image("bg_dots.png") repeat;
  71. 71. (seja criterioso)
  72. 72. dica 2 módulos: poucas linhas, comportamentos isolados, extensíveis, e testáveis.
  73. 73. estrutura base (reset, base styles) grid padrões módulos módulos contextualizados
  74. 74. css do módulo
  75. 75. /******************************************************************************* * * UI > Loader * * Animated loader for AJAX requests * *******************************************************************************/ @mixin loader_sprite_position($xoffset, $yoffset) { background-position: sprite-position($icon-sprite, loader_sprite, $xoffset, $yoffset); } .loader { width: 25px; height: 25px; display: none; } .loader b { display: block; width: 25px; height: 25px; background-image: sprite-url($icon-sprite); } .loader b, .loader .f1 { @include loader_sprite_position(-10px, -10px); } .loader .f2 { @include loader_sprite_position(-45px, -10px); } .loader .f3 { @include loader_sprite_position(-80px, -10px); } .loader .f4 { @include loader_sprite_position(-115px, -10px); } .loader .f5 { @include loader_sprite_position(-150px, -10px); } .loader .f6 { @include loader_sprite_position(-185px, -10px); } .loader .f7 { @include loader_sprite_position(-220px, -10px); } .loader .f8 { @include loader_sprite_position(-255px, -10px); }
  76. 76. css do módulo contextualizado
  77. 77. // On ui/_buttons.scss .bt-wrapper .loader { position: absolute; z-index: 4; right: 20px; top: 50%; margin-top: -9px; } // On modules/_checkoutAddressForm.scss .address-form .cep-input .loader { position: absolute; right: -33px; top: em(29px); }
  78. 78. javascript enxuto, auto-contido.
  79. 79. // Implements the animated loader for AJAX requests // Loader constructor // // * `placement`: Function that determines the loader's placement ns("EDEN.ui.Loader", function (placement) { if (!(this instanceof EDEN.ui.Loader)) { return new EDEN.ui.Loader(placement); } this.frame = 1; this.framesQty = 8; this.stack = []; this.animating = false; this.$loader = $("<div class='loader'><b> </b></div>"); this.$renderer = this.$loader.find("b"); this.placement = placement; this.init(); }); EDEN.ui.Loader.prototype = { // Properties // ---------- // Animation speed (in frames per second) fps : 20, // Fading speed fadeSpeed : 150, // Public methods // --------------
  80. 80. testável!
  81. 81. describe("EDEN.ui.Loader", function () { var Loader = EDEN.ui.Loader; beforeEach(function () { loadFixtures("loader.html"); }); afterEach(function () { $("body").find(".loader").remove(); }); it("accepts instance creation without new operator", function () { var newLoader = Loader(); expect(newLoader).toBeInstanceOf(Loader); }); it("inits the loader on creation", function () { var loader , oldInit = EDEN.ui.Loader.prototype.init ; EDEN.ui.Loader.prototype.init = jasmine.createSpy(); loader = new Loader(); expect(loader.init).toHaveBeenCalled(); EDEN.ui.Loader.prototype.init = oldInit; }); it("appends the loader to body as a default", function () { var loader = new Loader(); expect($("body").find(".loader").length).toEqual(1); }); it("appends the loader through an argument function", function () { var loader = new Loader(function ($loader) { $("#loader-placeholder").append($loader); }); expect($("#loader-placeholder").find(".loader").length).toEqual(1); }); });
  82. 82. "Mas tem muita coisa que não dá pra testar, né?"
  83. 83. "Mas testes atrapalham a entrega do projeto, né?"
  84. 84. a Baby possui 1144 specs de JavaScript até agora
  85. 85. falhas no jshint ou nas specs de javascript quebram o build
  86. 86. dica 3 javascript desacoplado e modularizado
  87. 87. mediator: ponto central de comunicação via pub/sub
  88. 88. MEDIATOR
  89. 89. nenhum módulo tem conhecimento do outro
  90. 90. MEDIATOR Mediator, me avisa quando sair o novo do Game of Thrones? Blz
  91. 91. MEDIATOR Mediator, me avisa quando sair o novo do Mythbusters? É nóish.
  92. 92. MEDIATOR Mediator, saiu um eppy novo de Game of Thrones. Subscribers, saiu um eppy novo de Game of Thrones! Ae, vou baixar, acho que vai ser feliz e tal =D
  93. 93. MEDIATOR Mediator, saiu um eppy novo de Mythbusters. Subscribers, saiu um eppy novo de Mythbusters! Ae, vou baixar!
  94. 94. os módulos só conhecem o mediator
  95. 95. módulos desacoplados, com comportamentos específicos e isolados
  96. 96. // Code inside ShippingAddressForm _registerInterests : function () { this.element.find(".cep-input") .on("keyup paste cut", this._onCepModification.bind(this)); }, _onCepModification : function (event) { if (this.isCepFilled()) { EDEN.mediator.trigger("shipping-cep-change", event.target.value); } else { EDEN.mediator.trigger("shipping-cep-incomplete", event.target.value); } }
  97. 97. // Code inside checkoutModule _registerInterests : function () { EDEN.mediator.on("shipping-cep-change", this._onShippingCepChange, this); this.shippingService.on("get-success", this._onShippingGetSuccess, this); }, _onShippingCepChange : function (cep) { this.shippingService.get(cep); } _onShippingGetSuccess : function (data) { EDEN.mediator.trigger("shipping-rate-change", data.rate); EDEN.mediator.trigger("delivery-estimate-change", data.estimate); }
  98. 98. // Code inside purchseInfo _registerInterests : function () { EDEN.mediator.on("shipping-rate-change", this._onShippingRateChange, this); EDEN.mediator.on("delivery-estimate-change", this._onDeliveryEstimateChange, this); }, _onShippingRateChange : function (rate) { this.updateShippingRate(rate); }, _onDeliveryEstimateChange : function (days) { this.updateDeliveryEstimate(days); }, updateShippingRate : function (rate) { var formatter = EDEN.currency.formatter; this.element.find(".shipping-rate").text(formatter(rate)); this.shippingRate = rate; this.updateTotal(); }, updateTotal : function () { var total = this.subtotal + this.shippingRate, formatter = EDEN.currency.formatter; this.element.find(".total").text(formatter(total)); EDEN.mediator.trigger("cart-total-change", total); }
  99. 99. // Code inside installmentSelector _registerInterests : function () { EDEN.mediator.on("cart-total-change", this._onCartTotalChange, this); }, _onCartTotalChange : function (total) { this.updateInstallments(total); }, updateInstallments : function (total) { // Updates the values }
  100. 100. você não precisa saber tudo isso de primeira.
  101. 101. addyosmani.com/largescalejavascript
  102. 102. aprenda javascript antes de se focar em um framework.
  103. 103. performance client-side
  104. 104. css/javascript minification/compression
  105. 105. lazy-load everything! o/
  106. 106. sprites e imagens inlines
  107. 107. sass +
  108. 108. não abuse de font-faces
  109. 109. testes a/b
  110. 110. isole os estilos e JS em classes, partials e módulos totalmente separados
  111. 111. <nav id="site-menu" class="site-menu"> <div class="site-menu-container"> <% if new_header? %> <%= render "layouts/open_site_nav" %> <% else %> <%= render "layouts/site_nav" %> <% end %> <% unless new_header? %> <%= render "layouts/search" %> <% end %> </div> </nav>
  112. 112. /******************************************************************************* * =Menu A *******************************************************************************/ .site-header-old .user-menu { position: absolute; right: perc(261px, $SITE_WIDTH); cursor: pointer; width: 213px; height: 63px; overflow: hidden; z-index: 600; } /******************************************************************************* * =Menu B *******************************************************************************/ .site-header-new .user-menu { position: absolute; right: perc(261px, $SITE_WIDTH); width: perc(150px, $SITE_WIDTH); height: em(63px); overflow: hidden; z-index: 600; }
  113. 113. AB-TESTING.md - como remover a versão perdedora
  114. 114. # A/B Testing on Baby Site This document lists all A/B tests currently being run on the project, and shortly introduces the method being used. ## Tests currently being run ### Site-wide #### Header design version * Test name: `header-version` * Starts at: `ApplicationController`, on `:before_filter` * Goal: When user goes to a success checkout page * Ends at: `orders#success` view * PR/Commits: [#664](https://github.com/Baby-com-br/troy/pull/664) To remove this test: * Remove the `new_header?` method and its `:helper_method` on `application_controller.rb` * Remove the `header_version` method and its `:helper_method` on `application_controller.rb` and ALL its calls. * Consolidate the correct `render` calls on `layouts/_header.html.erb` and `layouts/_site_menu.html.erb` * Remove the `site-header-<%= header_version %>` class on `layouts/_header.html.erb` * Remove the `header-version-<%= header_version %>` class on `layouts/_head.html.erb`, on the `<body>` tag * Remove the `finished` call on `baby-site/app/views/orders/success.html.erb` * On `modules/_mainSearchForm.scss`, remove the entire block related to the loser version, and on the winner version: (1) remove the comment header about the A/B test, (2) unprefix all selectors by removing either `.site-menu` (if the old header won) or `.site-header` (if the new header won) * On `layout/_user_menu.scss`, remove the entire block related to the loser version, and on the winner version: (1) remove the comment header about the A/B test, (2) unprefix all selectors by removing either `.site-header-new` (if the old header won) or `.site-header-old` (if the new header won) * On `ui/_section_header.scss`, remove the `.header-version-old .section-titles` and `.header-version-new .section-titles` blocks, and use the winner padding on `.section-titles`. * On `sections/_profile.scss`, remove the `.header-version-old .profile-header .site-menu` and `.header-version-new .profile-header .site-menu` blocks, and use the winner padding on `.profile-header .site-menu`. * On `layout/_main.scss`, delete the `.header-version-old .site-menu-container` block.
  115. 115. shiota, um dev front-end precisa saber back-end?
  116. 116. fulano(a), eu preciso saber cozinhar ou lavar roupa?
  117. 117. não, mas ajuda, né? ;D
  118. 118. você não precisa ser um nando vieira*. * @fnando - faz design, front-end, manja JS pacas, é um dev Ruby f*odido, e manja de SysOps
  119. 119. saber back-end melhora seu código.
  120. 120. saber back-end lhe dá mais controle.
  121. 121. saber back-end melhora a comunicação.
  122. 122. quando você deixa de perguntar apenas "como vou fazer isso" e passa a perguntar "como vou fazer isso da melhor maneira"...
  123. 123. ... você está no caminho certo.
  124. 124. divirta-se. sempre. =)
  125. 125. obrigado!slideshare.net/eshiota github.com/eshiota @shiota

×