javascript refactoring
Post on 20-Oct-2014
15.728 views
DESCRIPTION
Refactoring can either completely disrupt your project or make you go faster. This presentation will help you to avoid some pitfalls. It also demonstrates refactorings that you could apply straight away to make your code better.TRANSCRIPT
![Page 1: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/1.jpg)
REFACTORING
@szafranek
![Page 2: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/2.jpg)
We form a wonderful community.
Yet, we can learn a lot from other programming communities.
![Page 3: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/3.jpg)
REFACTORING
![Page 4: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/4.jpg)
Improving the design of code without changing its external behavior
![Page 5: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/5.jpg)
Refactoring is not...
If the changes affect external behavior, it’s rewriting, not refactoring.
![Page 6: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/6.jpg)
Refactoring is not...
For #1 excuse visit http://xkcd.com/303
![Page 7: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/7.jpg)
continuous
small steps
Refactoring should be done as a part of our every day workflow.Don’t wait for massive “big bang” refactorings.
![Page 8: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/8.jpg)
Investment
When to refactor?It’s an investment:- Makes change easier.- Helps find bugs.But comes with time and effort cost.
![Page 9: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/9.jpg)
enables you to go faster
May make little sense just before a deadline.
![Page 10: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/10.jpg)
makes code clear to other
people
Not machines
![Page 11: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/11.jpg)
Martin Fowler“Any fool can write code that a computer can understand.Good programmers write code that humans can understand.”
From the book “Refactoring”:http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672
![Page 12: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/12.jpg)
;It’s much more important to write code that will be easy to understand by other peoplethan just understood by a browser.
![Page 13: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/13.jpg)
clarityvs
performance
![Page 14: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/14.jpg)
clarityenables
performance
Some of you have heard that “Premature optimization is the root of all evil”.
It's easier to optimize clean code than to clean up "optimized" code.
![Page 15: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/15.jpg)
CODE SMELLS
![Page 16: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/16.jpg)
Code is like cheese.Some people find smelly what other find deliciously wonderful.
![Page 17: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/17.jpg)
duplication
It makes change harder.The rule of 3: the third time you copy something, it’s time to refactor.
![Page 18: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/18.jpg)
long methods
More than 10 lines is long. This rule is arbitrary to force you to stop and think when you exceed this size.A method should do one thing!
![Page 19: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/19.jpg)
switch/if statements
When they’re long and complex.
![Page 20: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/20.jpg)
speculative code
Remove any code that “may be useful later”. You can always recover it from version control.
Very often such code is NEVER nedeed and just confuses people who encounter it.
![Page 21: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/21.jpg)
comments
Comments become bad when used as a deodorant to hide messy code.
![Page 22: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/22.jpg)
STEP #0
![Page 23: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/23.jpg)
jslintjshint
Static analysis tools that detect mistakes and enforce clear style.Using lint was the single most important boost to my productivity in writing JS
![Page 24: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/24.jpg)
John Carmack“Anything that isn’t crystal clear to a static analysis toolprobably isn’t clear to your fellow programmers”.From John Carmack’s great article on static analysis tools:http://altdevblogaday.com/2011/12/24/static-code-analysis/
![Page 25: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/25.jpg)
STEP #1
![Page 26: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/26.jpg)
UNIT TESTS
Tests give a safety net. How else do you know that you didn’t change the behavior?
![Page 27: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/27.jpg)
JavaScript developer’s typical reaction to a question about unit tests
![Page 28: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/28.jpg)
STEP #2
Refactoring catalogue
![Page 29: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/29.jpg)
What you learned about webstandards and clean front-end code is still valid. These are the basics:* Separation of concerns.* Use CSS for styling.* Don’t inline JavaScript.* Assemble HTML in templates.
![Page 30: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/30.jpg)
InfoMode.prototype.activate = function (config) {
this.target = config.target; var entity = this.target.entity, entityName = entity.getProperName(), bulk = entity.getInfoModeString(), html = '<h1>' + entityName + '</h1><div class=specification>{bulk}</div>', millisecondsStart, millisecondsTotal, millisecondsEnd, millisecondsLeft;
if(entity.is('decoration')) { this.target.makeDynamic(); }
this.infoPanel.innerHTML = "";
if(entity.contract) { millisecondsStart = entity.contractStartTime; millisecondsTotal = entity.contract.requiredTime; millisecondsEnd = (new Date()).getTime() - this.target.entity.contractStartTime; millisecondsLeft = millisecondsTotal-millisecondsEnd;
if (entity.is('any house')) { if(this.target.entity.contractState === "started") { var gold = this.target.entity.getContractValue(); bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Gives you '+ gold + ' coins in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>'; } else { bulk = bulk || '<p>Please connect to road</p>'; } } else if (entity.is('farm')) { var food = this.target.entity.getContractValue(); bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Gives you ' + food + ' food in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>'; } else if (entity.is('ship')) { if(this.target.entity.contractState === "started") { bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Repair complete in <span id="timeLeft">' + utils.formatTime(millisecondsLeft) + '</span></p>'; } }
} else { if(entity.is('castle')) {
if(wooga.castle.playerData.upgradingCastle) { wooga.castle.CastleCompleteScreen.instance().show(); this.deactivate(); this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC); return; }
bulk = '<p><span class="population">Supported Population: ' + entity.definition.population + '</span></p>'; } else if(entity.is('decoration')) {
bulk = '<p>Nearby buildings get a '; var concatBoosts = false; if (entity.definition.goldBoost) { bulk += 'gold boost of ' + entity.definition.goldBoost + '%'; concatBoosts = true; } if (entity.definition.foodBoost) { if(concatBoosts) { bulk += '</p><p>and a '; } bulk += 'food boost of ' + entity.definition.foodBoost + '%.'; }
} }
this.infoPanel.innerHTML = html.replace('{bulk}', bulk);
this.manager.view.isFocusedEntityView = function (entityView) { return entityView === config.target; };
if(this.target.entity.contractState === "started") { var progress = document.querySelector('.progress div'), timer = document.getElementById('timeLeft'); progress.style.width = Math.floor((((new Date()).getTime() - millisecondsStart) / millisecondsTotal) * 100) + "%";
counter = setInterval(function () { var now = new Date().getTime(), timeFromStart = now - millisecondsStart; if((timeFromStart / millisecondsTotal) >= 1) { clearInterval(counter); } timer.innerHTML = utils.formatTime(millisecondsTotal - timeFromStart); progress.style.width = Math.floor((timeFromStart / millisecondsTotal) * 100) + "%"; }, 1000); }
utils.publish('view:entity/focused', { "entity": entity, "entityView": entity.entityView, "infoMode": this });
//TODO move to pubsub
// show boost info in influence area of decoration if (this.target instanceof wooga.castle.DecorationView) { this.target.entity.game.publish("decoration/showBoost", { entityView: this.target, x: this.target.entity.x, y: this.target.entity.y }); } // show boost of houses or farmfields in info mode if (this.target instanceof wooga.castle.FarmFieldView || this.target instanceof wooga.castle.HouseView) { if (this.target.entity.boost) { this.target.entity.entityView.showBoostInfo = true; } }
this.show();
};
Real code, one method, ~150 lines.
![Page 31: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/31.jpg)
InfoMode.prototype.activate = function (config) {
this.target = config.target; var entity = this.target.entity, entityName = entity.getProperName(), bulk = entity.getInfoModeString(), html = '<h1>' + entityName + '</h1><div class=specification>{bulk}</div>', millisecondsStart, millisecondsTotal, millisecondsEnd, millisecondsLeft;
if(entity.is('decoration')) { this.target.makeDynamic(); }
this.infoPanel.innerHTML = "";
if(entity.contract) { millisecondsStart = entity.contractStartTime; millisecondsTotal = entity.contract.requiredTime; millisecondsEnd = (new Date()).getTime() - this.target.entity.contractStartTime; millisecondsLeft = millisecondsTotal-millisecondsEnd;
if (entity.is('any house')) { if(this.target.entity.contractState === "started") { var gold = this.target.entity.getContractValue(); bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Gives you '+ gold + ' coins in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>'; } else { bulk = bulk || '<p>Please connect to road</p>'; } } else if (entity.is('farm')) { var food = this.target.entity.getContractValue(); bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Gives you ' + food + ' food in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>'; } else if (entity.is('ship')) { if(this.target.entity.contractState === "started") { bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Repair complete in <span id="timeLeft">' + utils.formatTime(millisecondsLeft) + '</span></p>'; } }
} else { if(entity.is('castle')) {
if(wooga.castle.playerData.upgradingCastle) { wooga.castle.CastleCompleteScreen.instance().show(); this.deactivate(); this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC); return; }
bulk = '<p><span class="population">Supported Population: ' + entity.definition.population + '</span></p>'; } else if(entity.is('decoration')) {
bulk = '<p>Nearby buildings get a '; var concatBoosts = false; if (entity.definition.goldBoost) { bulk += 'gold boost of ' + entity.definition.goldBoost + '%'; concatBoosts = true; } if (entity.definition.foodBoost) { if(concatBoosts) { bulk += '</p><p>and a '; } bulk += 'food boost of ' + entity.definition.foodBoost + '%.'; }
} }
this.infoPanel.innerHTML = html.replace('{bulk}', bulk);
this.manager.view.isFocusedEntityView = function (entityView) { return entityView === config.target; };
if(this.target.entity.contractState === "started") { var progress = document.querySelector('.progress div'), timer = document.getElementById('timeLeft'); progress.style.width = Math.floor((((new Date()).getTime() - millisecondsStart) / millisecondsTotal) * 100) + "%";
counter = setInterval(function () { var now = new Date().getTime(), timeFromStart = now - millisecondsStart; if((timeFromStart / millisecondsTotal) >= 1) { clearInterval(counter); } timer.innerHTML = utils.formatTime(millisecondsTotal - timeFromStart); progress.style.width = Math.floor((timeFromStart / millisecondsTotal) * 100) + "%"; }, 1000); }
utils.publish('view:entity/focused', { "entity": entity, "entityView": entity.entityView, "infoMode": this });
//TODO move to pubsub
// show boost info in influence area of decoration if (this.target instanceof wooga.castle.DecorationView) { this.target.entity.game.publish("decoration/showBoost", { entityView: this.target, x: this.target.entity.x, y: this.target.entity.y }); } // show boost of houses or farmfields in info mode if (this.target instanceof wooga.castle.FarmFieldView || this.target instanceof wooga.castle.HouseView) { if (this.target.entity.boost) { this.target.entity.entityView.showBoostInfo = true; } }
this.show();
};
Real code, one method, ~150 lines.
![Page 32: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/32.jpg)
Extract method
if(this.target.entity.contractState === "started") { var progress = document.querySelector('.progress div'), timer = document.getElementById('timeLeft'); progress.style.width = Math.floor((((new Date()).getTime() - millisecondsStart) / millisecondsTotal) * 100) + "%";
counter = setInterval(function () { var now = new Date().getTime(), timeFromStart = now - millisecondsStart; if((timeFromStart / millisecondsTotal) >= 1) { clearInterval(counter); } timer.innerHTML = utils.formatTime(millisecondsTotal - timeFromStart); progress.style.width = Math.floor((timeFromStart / millisecondsTotal) * 100) + "%"; }, 1000); }
this.showProgressBar(startTime,requiredTime);
Extract chunk that does one thing into a separate method.
![Page 33: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/33.jpg)
Replace comments
// show boost info in influence area of decoration
if (this.target instanceof wooga.castle.DecorationView) { this.target.entity.game.publish("decoration/showBoost", { entityView: this.target, x: this.target.entity.x, y: this.target.entity.y }); }
this.showBoosts(entity);
Well-named method makes comment unnecessary.
![Page 34: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/34.jpg)
Remove duplication
if (this.target.entity.is("decoration")) { this.target.entity.game.publish("decoration/showBoost", { entityView: this.target, x: this.target.entity.x, y: this.target.entity.y });}
var entity = this.target.entity;if (entity.is("decoration")) { entity.game.publish("decoration/showBoost", { entityView: this.target, x: entity.x, y: entity.y });}
![Page 35: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/35.jpg)
Replace temp with a query
var text = entity.getInfoModeString();infoPanel.innerHTML = '<div>' + text + '</div>';
infoPanel.innerHTML ='<div>' + entity.getInfoModeString() + '</div>';
If temporary variable is used only once, it doesn’t make sense to introduce it.Sometimes even two calls don’t justify a temporary variable, unless they’re expensive and you want to cache the results.
![Page 36: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/36.jpg)
Remove speculative code
switch (action) { case "move": break; case "destroy": break; default: break;}
![Page 37: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/37.jpg)
Use meaningful names
var p = this.current.params;var r = this.current.results;if (r.restProduct) { p.query = r.restProduct;}
var params = this.current.params;var results = this.current.results;if (results.restProduct) { params.query = results.restProduct;}
There are 2 hard things in CS: “cache invalidation and naming things”.
Leave compression to minifiers!
![Page 38: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/38.jpg)
Use polymorphism
if (entity.is('house')) { if(entity.contractState === "started") { var gold = entity.getContractValue(); bulk = '<p>Gives you '+ gold + ' coins</p>'; } else { bulk = bulk || '<p>Please connect to road</p>'; }} else if (entity.is('farm')) { var food = entity.getContractValue(); bulk = '<p>Gives you ' + food + ' food</p>';} else if (entity.is('ship')) { bulk = '<p>Repair complete in ' + time + '</span></p>';}
var bulk = entity.getInfoModeString();
Each entity class implements its own version of the method.
![Page 39: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/39.jpg)
InfoMode.prototype.activate = function (config) {
this.target = config.target; var entity = this.target.entity, entityName = entity.getProperName(), bulk = entity.getInfoModeString(), html = '<h1>' + entityName + '</h1><div class=specification>{bulk}</div>', millisecondsStart, millisecondsTotal, millisecondsEnd, millisecondsLeft;
if(entity.is('decoration')) { this.target.makeDynamic(); }
this.infoPanel.innerHTML = "";
if(entity.contract) { millisecondsStart = entity.contractStartTime; millisecondsTotal = entity.contract.requiredTime; millisecondsEnd = (new Date()).getTime() - this.target.entity.contractStartTime; millisecondsLeft = millisecondsTotal-millisecondsEnd;
if (entity.is('any house')) { if(this.target.entity.contractState === "started") { var gold = this.target.entity.getContractValue(); bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Gives you '+ gold + ' coins in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>'; } else { bulk = bulk || '<p>Please connect to road</p>'; } } else if (entity.is('farm')) { var food = this.target.entity.getContractValue(); bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Gives you ' + food + ' food in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>'; } else if (entity.is('ship')) { if(this.target.entity.contractState === "started") { bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Repair complete in <span id="timeLeft">' + utils.formatTime(millisecondsLeft) + '</span></p>'; } }
} else { if(entity.is('castle')) {
if(wooga.castle.playerData.upgradingCastle) { wooga.castle.CastleCompleteScreen.instance().show(); this.deactivate(); this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC); return; }
bulk = '<p><span class="population">Supported Population: ' + entity.definition.population + '</span></p>'; } else if(entity.is('decoration')) {
bulk = '<p>Nearby buildings get a '; var concatBoosts = false; if (entity.definition.goldBoost) { bulk += 'gold boost of ' + entity.definition.goldBoost + '%'; concatBoosts = true; } if (entity.definition.foodBoost) { if(concatBoosts) { bulk += '</p><p>and a '; } bulk += 'food boost of ' + entity.definition.foodBoost + '%.'; }
} }
this.infoPanel.innerHTML = html.replace('{bulk}', bulk);
this.manager.view.isFocusedEntityView = function (entityView) { return entityView === config.target; };
if(this.target.entity.contractState === "started") { var progress = document.querySelector('.progress div'), timer = document.getElementById('timeLeft'); progress.style.width = Math.floor((((new Date()).getTime() - millisecondsStart) / millisecondsTotal) * 100) + "%";
counter = setInterval(function () { var now = new Date().getTime(), timeFromStart = now - millisecondsStart; if((timeFromStart / millisecondsTotal) >= 1) { clearInterval(counter); } timer.innerHTML = utils.formatTime(millisecondsTotal - timeFromStart); progress.style.width = Math.floor((timeFromStart / millisecondsTotal) * 100) + "%"; }, 1000); }
utils.publish('view:entity/focused', { "entity": entity, "entityView": entity.entityView, "infoMode": this });
//TODO move to pubsub
// show boost info in influence area of decoration if (this.target instanceof wooga.castle.DecorationView) { this.target.entity.game.publish("decoration/showBoost", { entityView: this.target, x: this.target.entity.x, y: this.target.entity.y }); } // show boost of houses or farmfields in info mode if (this.target instanceof wooga.castle.FarmFieldView || this.target instanceof wooga.castle.HouseView) { if (this.target.entity.boost) { this.target.entity.entityView.showBoostInfo = true; } }
this.show();
};
InfoMode.prototype.activate = function (config) { this.target = config.target; var entity = this.target.entity;
if (entity.is('castle') && wooga.castle.playerData.upgradingCastle) { wooga.castle.CastleCompleteScreen.instance().show(); this.deactivate(); this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC); return; }
if (entity.is('decoration')) { this.target.makeDynamic(); }
this.infoPanel.innerHTML = '<h1>' + entity.getProperName() + '</h1><div class=specification>' + entity.getInfoModeString() + '</div>';
// RADAR: [szafranek] Why is this HERE? Moving it to worldView and listening to "entity/focused" looks better to me. this.manager.view.isFocusedEntityView = function (entityView) { return entityView === config.target; };
if (entity.contractState === wooga.castle.House.ContractState.STARTED) { this.showProgressBar(entity.contractStartTime, entity.contract.requiredTime); } else if (entity.contractState === wooga.castle.House.ContractState.CONSTRUCTION) { this.showProgressBar(entity.constructionStartTime, entity.contract.constructionTime); }
utils.publish('view:entity/focused', { "entity": entity, "entityView": entity.entityView, "infoMode": this });
this.showBoosts(entity);
this.show();
};
Original method after refactoring.
![Page 40: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/40.jpg)
Know where to stop.Ask yourself: is the further investment wortwhile?
![Page 41: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/41.jpg)
LEARNING MORE
![Page 42: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/42.jpg)
RefactoringMartin Fowler
![Page 43: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/43.jpg)
coderetreat.org
Organize one yourself if there’s none in your city!
![Page 44: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/44.jpg)
Robert C. Martin“Learning to write clean code is hard work.It requires more than just the knowledge of principles and patterns.You must sweat over it. You must practice it yourself, and watch yourself fail.You must watch others practice it and fail.”
From the book “Clean Code”:http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882
![Page 45: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/45.jpg)
Write code for people
Learn from others
@szafranek
![Page 46: JavaScript Refactoring](https://reader033.vdocuments.site/reader033/viewer/2022051012/544510b2afaf9f7e338b466f/html5/thumbnails/46.jpg)
photo credits
Ocial GDCginza_line
superfluity
_gee_
Pipistrula
fingersss
Łukasz Bałamut
mooong
diathesis
linder6580
chez loulou