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

3,882 views
3,768 views

Published on

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/

Published in: Technology

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

  1. 1. os desafios do desenvolvimentode front-end em um e-commerce@shiota 2013
  2. 2. olá!slideshare.net/eshiotagithub.com/eshiota@shiota
  3. 3. front-end engineer@
  4. 4. DEV
  5. 5. e-commerce 101em alguns slides
  6. 6. =)
  7. 7. taxa de conversãodos usuários que entram no site, quantosfinalizam uma compra?
  8. 8. ticket médioem média, quanto os usuários gastampor 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. complexoindecisoexigenteinexperientedecididocuidadosoexperiente
  14. 14. ser humano, comotodos nós =)
  15. 15. o que faz o usuárioabandonar o carrinho?
  16. 16. alto custo de frete$
  17. 17. não estão prontospara finalizar?
  18. 18. produtos muito caros$
  19. 19. guardam para depois
  20. 20. não mencionouclaramente o frete?
  21. 21. sem guest checkout
  22. 22. formulário commuitas informações
  23. 23. checkout complexo
  24. 24. website lento
  25. 25. taxas extras
  26. 26. falta de opçõesde pagamento
  27. 27. entrega demorada
  28. 28. spam de ofertas
  29. 29. site não funciona=(
  30. 30. como o front-end podemelhorar a conversão?
  31. 31. formulário com muitas informaçõescheckout complexowebsite lentosite não funciona
  32. 32. velocidade da páginainterface estáveldetalhes = emotion designvalidação de novas hipóteses
  33. 33. desafios de front-end(agora a palestra começa =P)
  34. 34. múltiplos desenvolvedoresdesenvolvimento escalávelperformance client-sidetestes a/b
  35. 35. trabalhando comvá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 teruma visão diferente ecomplementar. =)
  43. 43. code smell performancesintaxe arquitetura
  44. 44. mantenha um codestandard 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 maiscriteriosos com o que fazem.
  51. 51. desenvolvimentoescalá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 facilmentealterável/adaptável.
  55. 55. dica 1usem pre-processors de CSS.sério. agora. já. eu espero.
  56. 56. sass+
  57. 57. variáveis, mixins efunçõ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 modularizadosem partials
  62. 62. app/assets/stylesheets/base/_functions.scss_mixins.scss_variables.scssui/_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 spritesacelera 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 imageeconomiza requests.
  70. 70. /* Compiled CSS */background: #f5f3fb url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAQCAMAAAAcVM5PAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAAlQTFRF5+TW////////4qZUpQAAAAN0Uk5T//8A18oNQQAAACBJREFUeNpiYGBgAgMGBkYog4mJXAbILAiDkVxzAAIMAEMOAPMId2OWAAAAAElFTkSuQmCC) repeat;/* Generates a base64 image */background: #f5f3eb inline-image("bg_dots.png") repeat;
  71. 71. (seja criterioso)
  72. 72. dica 2módulos: poucas linhas,comportamentos isolados,extensíveis, e testáveis.
  73. 73. estrutura base (reset, base styles)gridpadrõesmódulosmó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ódulocontextualizado
  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 loaders placementns("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 speedfadeSpeed : 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 quenão dá pra testar, né?"
  83. 83. "Mas testes atrapalham aentrega do projeto, né?"
  84. 84. a Baby possui 1144 specs deJavaScript até agora
  85. 85. falhas no jshint ou nas specsde javascript quebram o build
  86. 86. dica 3javascript desacoplado emodularizado
  87. 87. mediator: ponto central decomunicação via pub/sub
  88. 88. MEDIATOR
  89. 89. nenhum módulo temconhecimento do outro
  90. 90. MEDIATORMediator, me avisa quandosair o novo do Game ofThrones?Blz
  91. 91. MEDIATORMediator, me avisa quandosair o novo do Mythbusters?É nóish.
  92. 92. MEDIATORMediator, saiu um eppy novode Game of Thrones.Subscribers, saiu um eppynovo de Game of Thrones!Ae, vou baixar, achoque vai ser feliz e tal=D
  93. 93. MEDIATORMediator, saiu um eppy novode Mythbusters.Subscribers, saiu um eppynovo de Mythbusters!Ae, vou baixar!
  94. 94. os módulos só conhecemo mediator
  95. 95. módulos desacoplados, comcomportamentos específicos eisolados
  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 sabertudo isso de primeira.
  101. 101. addyosmani.com/largescalejavascript
  102. 102. aprenda javascript antes dese focar em um framework.
  103. 103. performanceclient-side
  104. 104. css/javascriptminification/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 emclasses, partials e módulostotalmente 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 - comoremover a versão perdedora
  114. 114. # A/B Testing on Baby SiteThis document lists all A/B tests currently being run on the project, andshortly 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 theloser version, and on the winner version: (1) remove the comment header aboutthe A/B test, (2) unprefix all selectors by removing either `.site-menu` (ifthe old header won) or `.site-header` (if the new header won)* On `layout/_user_menu.scss`, remove the entire block related to theloser version, and on the winner version: (1) remove the comment header aboutthe A/B test, (2) unprefix all selectors by removing either `.site-header-new` (ifthe 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 paddingon `.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 paddingon `.profile-header .site-menu`.* On `layout/_main.scss`, delete the `.header-version-old .site-menu-container` block.
  115. 115. shiota, um dev front-endprecisa saber back-end?
  116. 116. fulano(a), eu preciso sabercozinhar ou lavar roupa?
  117. 117. não, mas ajuda, né? ;D
  118. 118. você não precisa ser umnando vieira*.* @fnando - faz design, front-end, manja JS pacas, é um dev Ruby f*odido, e manja de SysOps
  119. 119. saber back-endmelhora seu código.
  120. 120. saber back-endlhe dá mais controle.
  121. 121. saber back-endmelhora a comunicação.
  122. 122. quando você deixa de perguntarapenas "como vou fazer isso" epassa a perguntar "como voufazer isso da melhor maneira"...
  123. 123. ... você está nocaminho certo.
  124. 124. divirta-se. sempre. =)
  125. 125. obrigado!slideshare.net/eshiotagithub.com/eshiota@shiota

×