It’s never too late to fight your legacy

It’s never too late to fight your legacy

http://www.slideshare.net/matenadasdi1/its-never-too-late-to-fight-your-legacy

Every frontend developer reaches the point where continuous feature development and rapid changes makes it hard to maintain a codebase in large scale, and the complexity starts to climb up to the sky. Instability and slower development is not an option for us, so we had to experiment with new methods and technologies. Unit testing was not a common technique on client-side in recent years, but over a certain amount of complexity it's essential.

At Ustream we feel the need of full coverage including unit testing and end-to-end testing and bringing our structured framework into play with continuous integration on the frontend side. My presentation provides insight into our first problems, tells where we are on this bumpy road, and what is our plan to maintain this state in the future.

7695c800a46abf4a8ad2e975379d6cba?s=128

Mate Nadasdi

April 24, 2014
Tweet

Transcript

  1. @matenadasdi Front-end Developer at Ustream

  2. Why we think in large scale

  3. over 80 million active visitors / month 391,273,889 viewer hours

    last year
  4. It’s never too late to fight your legacy our front-end

    dev achievements from last year
  5. What is legacy? Legacy is not bad code it’s old

    or just over-iterated.
  6. A long time ago in a galaxy far, far away...

    Let’s take a look back in general
  7. An average javascript codebase 2-3 years ago feature based classes

    (example Gallery.js) no tests low perf optimization (no tools) app.Gallery = Class({ page: 0, ! init: function () { this.wrapper = $(‘.gallery’); this.content = this.wrapper.find(‘.content’); this.wrapper.on( ‘click’, ‘.pager’, this.onPagerClick.bind(this) ); ! new CustomSelect(‘.custom-select’); ! _qaq.push([‘_trackEvent’, ‘gallery’, ‘load’, ‘init’]; }, ! onPagerClick: function () { this.page++; this.getPageData(this.page); }, ! getPageData: function () { $.getJSON(‘/gallery.json’, this.onResponse.bind(this)); }, ! onResponse: function (resp) { this.content.html(resp.html); } });
  8. We all know that this approach didn't work in large

    scale
  9. It would be nice to drop everything but of course

    it’s not an option SOUNDS FAMILIAR?
  10. This was exactly our situation at Ustream.

  11. × new re-designs and layouts nearly every year × using

    History API started a transformation × rapidly growing complexity on the client side It got worse because…
  12. That’s enough! We needed more Stability & Scalability Main decision

    in the browser too
  13. Ok! Let’s start testing… Wait, what?! We can’t? First problem

  14. Why? × No separation between logic and its representation ×

    Huge “all-in-one” feature based class system !
  15. We needed a new structure Workshops

  16. Not the framework, but the way of thinking is what

    really matters
  17. Think in layers with responsibilities

  18. DATA MANIPULATION LAYER × simple data proxy between source and

    UI Logic × observable data object × planning to integrate ES7 Object.observe() https://github.com/Polymer/observe-js Model COMMUNICATION TYPES UI LAYER AJAX WebStorage Cookies Socket Ustream Flash API Longpoll Embeds
  19. Take a breath check where you are Create prototypes Prototyping,

    search for possibilities
  20. Logics Models DATASOURCE LAYER Sync Socket (full-duplex) Async DATA MANIPULATION

    LAYER UI LAYER AJAX WebStorage Cookies Socket Ustream Flash API Longpoll Embeds
  21. Logics DATASOURCE LAYER Sync Socket Async AJAX WebStorage Cookies Socket

    Ustream Flash API Longpoll Embeds Models Views Controllers DOM manipulate notify set data get control events DATA MANIPULATION LAYER
  22. \o/ × We created a really small modularized base (under

    10kB) × There was no “first idea” problem anymore × It was just the beginning! 10kB vs 600+ files New structure specified
  23. Modules vs simple assignment Esprima for code modification automation https://github.com/ariya/esprima

    Refactor automation to
  24. Continuous integration × New features are developed in new style

    with tests × Refactor & new tests in small packages by features Integration started
  25. Unit testing is not enough  Writing tests like there's

    no tomorrow
  26. Strive to reach full coverage in every field!

  27. × dependency injection with RequireJS × mocking with Sinon and

    Squire × for business logic and complex controllers Our testing pyramid - Unit testing mocha + + + PhantomJS Sinon.js Unit testing
  28. × Node.js based navigation scripting × experiments with TrifleJS ×

    for view / controller testing Casper.js + + PhantomJS SlimerJS mocha + + + PhantomJS Sinon.js Unit testing Functional testing Our testing pyramid - Functional testing
  29. × we have a dedicated TA team for years ×

    hundreds of tests on every platform already × testing complex features (payment, purchase flows, etc) Casper.js + + PhantomJS SlimerJS mocha + + + PhantomJS Sinon.js Unit testing Functional testing TA team selenium testing Selenium + Java Our testing pyramid - TA selenium testing
  30. × manual QA team × we support them with automated

    tools Casper.js + + PhantomJS SlimerJS mocha + + + PhantomJS Sinon.js Unit testing Functional testing TA team selenium testing Selenium + Java Manual QA team UI testing tools & debugging tools Our testing pyramid - manual QA testing
  31. Screenshot comparison tool

  32. Internal Chrome DevTools extension

  33. Create your own standards and rules ! selector is not

    allowed here undefined is not a function ‘index’ is not defined your line is too long Invalid number of arguments Unused parameter unresolved function Standards & rules creation
  34. Unify your workflow with automation Workflow automation we use grunt

  35. Remind others to obey the new rules https://www.flickr.com/photos/ericflexyourhead/5811251629

  36. Integrate into your CI tool CI integration

  37. Check your style as early as possible use hooks More

    code quality tools
  38. Do not forget semantics create your own plugins, use ESLint

    and Esprima ESLint
  39. Measure code complexity Plato: grunt complexity report in Jenkins:

  40. Code coverage essential for unit testing Karma + Istanbul +

    IDE integration:
  41. Performance is a feature!

  42. A lot of possibilities × measuring Navigation Timing & Resource

    Timing API × tracking memory allocation with Web Performance API × WebPageTest API automation × planning to create peak alerts memory allocation navigation timing
  43. new Date(); This is where we are × over 500+

    files changed × hundreds of unit tests & functional tests × every important part is modularized × we are ready for async module loading too
  44. and many more to come

  45. Thank you! @matenadasdi