it's never too late to fight your legacy!
DESCRIPTION
It's never too late to fight your legacy! https://speakerdeck.com/matenadasdi/its-never-too-late-to-fight-your-legacy 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.TRANSCRIPT
@matenadasdiFront-end Developer at Ustream
Why we think in large scale
over 80 million active visitors / month
391,273,889 viewer hours last year
It’s never too late to fight your legacy
our front-end dev achievements from last year
What is legacy?Legacy is not bad code
it’s old or just over-iterated.
A long time ago in a galaxy far, far away...
Let’s take a look back in general
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); } });
We all know that this approach didn't work in large scale
It would be nice to drop everything but of course it’s not an option
SOUNDS FAMILIAR?
This was exactly our situation at Ustream.
× 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…
That’s enough!
We needed more Stability & Scalability
Main decision
in the browser too
Ok! Let’s start testing…
Wait, what?!
We can’t?
First problem
Why?
× No separation between logic and its representation
× Huge “all-in-one” feature based class system
!
We needed a new structure
Workshops
Not the framework, but the way of thinking
is what really matters
Think in layers with responsibilities
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 APILongpoll Embeds
Take a breath check where you are Create prototypes
Prototyping, search for possibilities
Logics Models
DATASOURCE LAYER
Sync Socket (full-duplex)Async
DATA MANIPULATION LAYER
UI LAYER
AJAX WebStorage Cookies Socket Ustream Flash APILongpoll Embeds
Logics
DATASOURCE LAYER
Sync SocketAsync
AJAX WebStorage Cookies Socket Ustream Flash APILongpoll Embeds
Models
Views
Controllers
DOM
manipulate
notify
set dataget
control
events
DATA MANIPULATION LAYER
\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
Modules vs simple assignment
Esprima for code modification automation https://github.com/ariya/esprima
Refactor automation
to
Continuous integration
× New features are developed in new style with tests
× Refactor & new tests in small packages by features
Integration started
Unit testing is not enough
!Writing tests like there's no tomorrow
Strive to reach full coverage in every field!
× dependency injection with RequireJS
× mocking with Sinon and Squire
× for business logic and complex controllers
Our testing pyramid - Unit testing
mocha + + + PhantomJSSinon.jsUnit testing
× Node.js based navigation scripting
× experiments with TrifleJS
× for view / controller testing
Casper.js + +PhantomJS SlimerJS
mocha + + + PhantomJSSinon.jsUnit testing
Functional testing
Our testing pyramid - Functional testing
× 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 + + + PhantomJSSinon.jsUnit testing
Functional testing
TA team selenium testing Selenium + Java
Our testing pyramid - TA selenium testing
× manual QA team
× we support them with automated tools
Casper.js + +PhantomJS SlimerJS
mocha + + + PhantomJSSinon.jsUnit testing
Functional testing
TA team selenium testing Selenium + Java
Manual QA team UI testing tools & debugging tools
Our testing pyramid - manual QA testing
Screenshot comparison tool
Internal Chrome DevTools extension
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
Unify your workflow with automation
Workflow automation
we use grunt
Remind others to obey the new rules
https://www.flickr.com/photos/ericflexyourhead/5811251629
Integrate into your CI tool
CI integration
Check your style as early as possible use hooks
More code quality tools
Do not forget semantics create your own plugins, use ESLint and Esprima
ESLint
Measure code complexity
Plato:
grunt complexity report in Jenkins:
Code coverage essential for unit testing
Karma + Istanbul + IDE integration:
Performance is a feature!
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
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
and many more to come
Thank you!@matenadasdi