SlideShare a Scribd company logo
REFACTORING

@szafranek
We form a wonderful community.

Yet, we can learn a lot from other programming communities.
REFACTORING
Improving
the design of code
without changing
its external behavior
Refactoring is not...




If the changes affect external behavior, it’s rewriting, not refactoring.
Refactoring is not...




For #1 excuse visit http://xkcd.com/303
continuous
            small steps
Refactoring should be done as a part of our every day workflow.
Don’t wait for massive “big bang” refactorings.
Investment
When to refactor?
It’s an investment:
- Makes change easier.
- Helps find bugs.
But comes with time and effort cost.
enables you to
            go faster

May make little sense just before a deadline.
makes code
               clear to other
                  people

Not machines
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
;
It’s much more important to write code that will be easy to understand by other people
than just understood by a browser.
clarity
     vs
performance
clarity
          enables
        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.
CODE SMELLS
Code is like cheese.
Some people find smelly what other find deliciously wonderful.
duplication

It makes change harder.
The rule of 3: the third time you copy something, it’s time to refactor.
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!
switch/if
       statements
When they’re long and complex.
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.
comments

Comments become bad when used as a deodorant to hide messy code.
STEP #0
jslint
                                                                jshint
Static analysis tools that detect mistakes and enforce clear style.
Using lint was the single most important boost to my productivity in writing JS
John Carmack
“Anything that isn’t crystal clear to a static analysis tool
probably 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/
STEP #1
UNIT TESTS

Tests give a safety net. How else do you know that you didn’t change the behavior?
JavaScript developer’s typical reaction to a question about unit tests
STEP #2

Refactoring catalogue
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.
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 {
Real   code, one method, ~150 lines.
                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
};

           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.
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.
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.
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
    });
}
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.
Remove speculative code

switch (action) {
    case "move":
        break;
    case "destroy":
        break;
    default:
        break;
}
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!
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.
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 +                                                                                                  InfoMode.prototype.activate = function (config) {
                        ' food in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>';           this.target = config.target;
                } else if (entity.is('ship')) {
                    if(this.target.entity.contractState === "started") {
                                                                                                                    var entity = this.target.entity;
                        bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Repair
        complete in <span id="timeLeft">' +                                                                          if (entity.is('castle') && wooga.castle.playerData.upgradingCastle) {
                            utils.formatTime(millisecondsLeft) + '</span></p>';
                    }
                                                                                                                         wooga.castle.CastleCompleteScreen.instance().show();
                }                                                                                                        this.deactivate();
                                                                                                                         this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC);
               }
               else {
                                                                                                                         return;
                   if(entity.is('castle')) {                                                                         }

                       if(wooga.castle.playerData.upgradingCastle) {
                           wooga.castle.CastleCompleteScreen.instance().show();
                                                                                                                     if (entity.is('decoration')) {
                           this.deactivate();                                                                            this.target.makeDynamic();
                           this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC);                           }
                           return;
                       }
                                                                                                                    this.infoPanel.innerHTML = '<h1>' + entity.getProperName() + '</h1><div
                       bulk = '<p><span class="population">Supported Population: ' +                            class=specification>' + entity.getInfoModeString() + '</div>';
                           entity.definition.population
                       + '</span></p>';
                   } else if(entity.is('decoration')) {                                                             // RADAR: [szafranek] Why is this HERE? Moving it to worldView and listening to
                                                                                                                "entity/focused" looks better to me.
                       bulk = '<p>Nearby buildings get a ';
                       var concatBoosts = false;
                                                                                                                    this.manager.view.isFocusedEntityView = function (entityView) {
                       if (entity.definition.goldBoost) {                                                               return entityView === config.target;
                             bulk += 'gold boost of ' + entity.definition.goldBoost + '%';                          };
                             concatBoosts = true;
                       }
                       if (entity.definition.foodBoost) {                                                           if (entity.contractState === wooga.castle.House.ContractState.STARTED) {
                           if(concatBoosts) {                                                                           this.showProgressBar(entity.contractStartTime,
                               bulk += '</p><p>and a ';
                           }
                                                                                                                entity.contract.requiredTime);
                           bulk += 'food boost of ' + entity.definition.foodBoost + '%.';                           } else if (entity.contractState ===
                       }                                                                                        wooga.castle.House.ContractState.CONSTRUCTION) {
                   }
                                                                                                                        this.showProgressBar(entity.constructionStartTime,
               }                                                                                                entity.contract.constructionTime);
                                                                                                                    }
               this.infoPanel.innerHTML = html.replace('{bulk}', bulk);

               this.manager.view.isFocusedEntityView = function (entityView) {                                       utils.publish('view:entity/focused', {
                   return entityView === config.target;                                                                  "entity": entity,
               };
                                                                                                                         "entityView": entity.entityView,
            if(this.target.entity.contractState === "started") {                                                         "infoMode": this
                var progress = document.querySelector('.progress div'),                                              });
                    timer = document.getElementById('timeLeft');
                progress.style.width = Math.floor((((new Date()).getTime() - millisecondsStart) /
        millisecondsTotal) * 100) + "%";                                                                             this.showBoosts(entity);

                   counter = setInterval(function () {
                       var now = new Date().getTime(), timeFromStart = now - millisecondsStart;
                                                                                                                     this.show();
                       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();




Original method after refactoring.
        };
Know where to stop.
Ask yourself: is the further investment wortwhile?
LEARNING MORE
Refactoring
Martin Fowler
coderetreat.org
Organize one yourself if there’s none in your city!
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
Write code for people

Learn from others


@szafranek
_gee_                 fingersss
chez loulou           diathesis
linder6580           Pipistrula
ginza_line         Ocial GDC
superfluity      Łukasz Bałamut
mooong




photo credits

More Related Content

What's hot

Lab #2: Introduction to Javascript
Lab #2: Introduction to JavascriptLab #2: Introduction to Javascript
Lab #2: Introduction to Javascript
Walid Ashraf
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
Angel Garcia Olloqui
 
Javascript
JavascriptJavascript
Javascript
Manav Prasad
 
Object Oriented PHP - PART-1
Object Oriented PHP - PART-1Object Oriented PHP - PART-1
Object Oriented PHP - PART-1
Jalpesh Vasa
 
Javascript functions
Javascript functionsJavascript functions
Javascript functions
Alaref Abushaala
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 Function
Kent Huang
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
Rowan Merewood
 
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
Doug Jones
 
Javascript - Tutorial
Javascript - TutorialJavascript - Tutorial
Javascript - Tutorialadelaticleanu
 
Advanced Javascript
Advanced JavascriptAdvanced Javascript
Advanced Javascript
Dhruvin Shah
 
clean code book summary - uncle bob - English version
clean code book summary - uncle bob - English versionclean code book summary - uncle bob - English version
clean code book summary - uncle bob - English version
saber tabatabaee
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
Peter Gfader
 
JavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UXJavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UX
JWORKS powered by Ordina
 
Java best practices
Java best practicesJava best practices
Java best practices
Ray Toal
 
TDD Training
TDD TrainingTDD Training
TDD Training
Manuela Grindei
 
Introduction to Javascript
Introduction to JavascriptIntroduction to Javascript
Introduction to Javascript
Amit Tyagi
 
Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]
Aaron Gustafson
 
Spring boot
Spring bootSpring boot
JavaScript - Chapter 6 - Basic Functions
 JavaScript - Chapter 6 - Basic Functions JavaScript - Chapter 6 - Basic Functions
JavaScript - Chapter 6 - Basic Functions
WebStackAcademy
 
JavaScript Programming
JavaScript ProgrammingJavaScript Programming
JavaScript Programming
Sehwan Noh
 

What's hot (20)

Lab #2: Introduction to Javascript
Lab #2: Introduction to JavascriptLab #2: Introduction to Javascript
Lab #2: Introduction to Javascript
 
Writing clean code
Writing clean codeWriting clean code
Writing clean code
 
Javascript
JavascriptJavascript
Javascript
 
Object Oriented PHP - PART-1
Object Oriented PHP - PART-1Object Oriented PHP - PART-1
Object Oriented PHP - PART-1
 
Javascript functions
Javascript functionsJavascript functions
Javascript functions
 
Clean Code: Chapter 3 Function
Clean Code: Chapter 3 FunctionClean Code: Chapter 3 Function
Clean Code: Chapter 3 Function
 
Living With Legacy Code
Living With Legacy CodeLiving With Legacy Code
Living With Legacy Code
 
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
JavaScript: The Good Parts Or: How A C# Developer Learned To Stop Worrying An...
 
Javascript - Tutorial
Javascript - TutorialJavascript - Tutorial
Javascript - Tutorial
 
Advanced Javascript
Advanced JavascriptAdvanced Javascript
Advanced Javascript
 
clean code book summary - uncle bob - English version
clean code book summary - uncle bob - English versionclean code book summary - uncle bob - English version
clean code book summary - uncle bob - English version
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
JavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UXJavaScript Basics and Best Practices - CC FE & UX
JavaScript Basics and Best Practices - CC FE & UX
 
Java best practices
Java best practicesJava best practices
Java best practices
 
TDD Training
TDD TrainingTDD Training
TDD Training
 
Introduction to Javascript
Introduction to JavascriptIntroduction to Javascript
Introduction to Javascript
 
Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]Fundamental JavaScript [UTC, March 2014]
Fundamental JavaScript [UTC, March 2014]
 
Spring boot
Spring bootSpring boot
Spring boot
 
JavaScript - Chapter 6 - Basic Functions
 JavaScript - Chapter 6 - Basic Functions JavaScript - Chapter 6 - Basic Functions
JavaScript - Chapter 6 - Basic Functions
 
JavaScript Programming
JavaScript ProgrammingJavaScript Programming
JavaScript Programming
 

Viewers also liked

Refactoring - An Introduction
Refactoring - An IntroductionRefactoring - An Introduction
Refactoring - An Introduction
Giorgio Vespucci
 
Refactoring Tips by Martin Fowler
Refactoring Tips by Martin FowlerRefactoring Tips by Martin Fowler
Refactoring Tips by Martin Fowler
Igor Crvenov
 
LINSEN an efficient approach to split identifiers and expand abbreviations
LINSEN an efficient approach to split identifiers and expand abbreviationsLINSEN an efficient approach to split identifiers and expand abbreviations
LINSEN an efficient approach to split identifiers and expand abbreviations
Valerio Maggio
 
[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기
[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기
[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기
우영 주
 
Improving Software Maintenance using Unsupervised Machine Learning techniques
Improving Software Maintenance using Unsupervised Machine Learning techniquesImproving Software Maintenance using Unsupervised Machine Learning techniques
Improving Software Maintenance using Unsupervised Machine Learning techniques
Valerio Maggio
 
Impact of Restful Web Architecture on Performance and Scalability
Impact of Restful Web Architecture on Performance and ScalabilityImpact of Restful Web Architecture on Performance and Scalability
Impact of Restful Web Architecture on Performance and Scalability
Sanchit Gera
 
Eclipse refactoring
Eclipse refactoringEclipse refactoring
Eclipse refactoring
srcid
 
Database Refactoring
Database RefactoringDatabase Refactoring
Database Refactoring
Anton Keks
 
Refactoring 101
Refactoring 101Refactoring 101
Refactoring 101
Adam Culp
 

Viewers also liked (9)

Refactoring - An Introduction
Refactoring - An IntroductionRefactoring - An Introduction
Refactoring - An Introduction
 
Refactoring Tips by Martin Fowler
Refactoring Tips by Martin FowlerRefactoring Tips by Martin Fowler
Refactoring Tips by Martin Fowler
 
LINSEN an efficient approach to split identifiers and expand abbreviations
LINSEN an efficient approach to split identifiers and expand abbreviationsLINSEN an efficient approach to split identifiers and expand abbreviations
LINSEN an efficient approach to split identifiers and expand abbreviations
 
[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기
[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기
[Toolcon2014] WebStorm에서 자바스크립트 리팩토링하기
 
Improving Software Maintenance using Unsupervised Machine Learning techniques
Improving Software Maintenance using Unsupervised Machine Learning techniquesImproving Software Maintenance using Unsupervised Machine Learning techniques
Improving Software Maintenance using Unsupervised Machine Learning techniques
 
Impact of Restful Web Architecture on Performance and Scalability
Impact of Restful Web Architecture on Performance and ScalabilityImpact of Restful Web Architecture on Performance and Scalability
Impact of Restful Web Architecture on Performance and Scalability
 
Eclipse refactoring
Eclipse refactoringEclipse refactoring
Eclipse refactoring
 
Database Refactoring
Database RefactoringDatabase Refactoring
Database Refactoring
 
Refactoring 101
Refactoring 101Refactoring 101
Refactoring 101
 

Similar to JavaScript Refactoring

Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
Ryunosuke SATO
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
Ankit Rastogi
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of usOSCON Byrum
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
Pavel Lahoda
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon Berlin
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
Nishan Subedi
 
Diving in the Flex Data Binding Waters
Diving in the Flex Data Binding WatersDiving in the Flex Data Binding Waters
Diving in the Flex Data Binding Waters
michael.labriola
 
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
Daniel Fisher
 
! Modernizr v2.0.6 httpwww.modernizr.com Copyri.docx
!  Modernizr v2.0.6  httpwww.modernizr.com   Copyri.docx!  Modernizr v2.0.6  httpwww.modernizr.com   Copyri.docx
! Modernizr v2.0.6 httpwww.modernizr.com Copyri.docx
MARRY7
 
Asp.net state management
Asp.net state managementAsp.net state management
Asp.net state management
priya Nithya
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
pootsbook
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 
Exercises
ExercisesExercises
Exercises
maamir farooq
 
Javascript 1
Javascript 1Javascript 1
Javascript 1
pavishkumarsingh
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScript
kvangork
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascript
kvangork
 
Mobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhoneMobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhoneMohammad Shaker
 
Backbone - TDC 2011 Floripa
Backbone - TDC 2011 FloripaBackbone - TDC 2011 Floripa
Backbone - TDC 2011 Floripa
Rafael Felix da Silva
 

Similar to JavaScript Refactoring (20)

Clean Javascript
Clean JavascriptClean Javascript
Clean Javascript
 
Ten useful JavaScript tips & best practices
Ten useful JavaScript tips & best practicesTen useful JavaScript tips & best practices
Ten useful JavaScript tips & best practices
 
Big Data for each one of us
Big Data for each one of usBig Data for each one of us
Big Data for each one of us
 
Improving android experience for both users and developers
Improving android experience for both users and developersImproving android experience for both users and developers
Improving android experience for both users and developers
 
Droidcon2013 android experience lahoda
Droidcon2013 android experience lahodaDroidcon2013 android experience lahoda
Droidcon2013 android experience lahoda
 
Virtual Madness @ Etsy
Virtual Madness @ EtsyVirtual Madness @ Etsy
Virtual Madness @ Etsy
 
Backbone Basics with Examples
Backbone Basics with ExamplesBackbone Basics with Examples
Backbone Basics with Examples
 
Rhino Mocks
Rhino MocksRhino Mocks
Rhino Mocks
 
Diving in the Flex Data Binding Waters
Diving in the Flex Data Binding WatersDiving in the Flex Data Binding Waters
Diving in the Flex Data Binding Waters
 
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
2008 - TechDays PT: WCF, JSON and AJAX for performance and manageability
 
! Modernizr v2.0.6 httpwww.modernizr.com Copyri.docx
!  Modernizr v2.0.6  httpwww.modernizr.com   Copyri.docx!  Modernizr v2.0.6  httpwww.modernizr.com   Copyri.docx
! Modernizr v2.0.6 httpwww.modernizr.com Copyri.docx
 
Asp.net state management
Asp.net state managementAsp.net state management
Asp.net state management
 
Backbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVCBackbone.js — Introduction to client-side JavaScript MVC
Backbone.js — Introduction to client-side JavaScript MVC
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 
Exercises
ExercisesExercises
Exercises
 
Javascript 1
Javascript 1Javascript 1
Javascript 1
 
Object-Oriented JavaScript
Object-Oriented JavaScriptObject-Oriented JavaScript
Object-Oriented JavaScript
 
Object-Oriented Javascript
Object-Oriented JavascriptObject-Oriented Javascript
Object-Oriented Javascript
 
Mobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhoneMobile Software Engineering Crash Course - C06 WindowsPhone
Mobile Software Engineering Crash Course - C06 WindowsPhone
 
Backbone - TDC 2011 Floripa
Backbone - TDC 2011 FloripaBackbone - TDC 2011 Floripa
Backbone - TDC 2011 Floripa
 

More from Krzysztof Szafranek

Mobile Game Development
Mobile Game DevelopmentMobile Game Development
Mobile Game Development
Krzysztof Szafranek
 
ESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. NowESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. Now
Krzysztof Szafranek
 
Getting the Most out of Your Tools
Getting the Most out of Your ToolsGetting the Most out of Your Tools
Getting the Most out of Your Tools
Krzysztof Szafranek
 
What Lies Ahead for HTML5
What Lies Ahead for HTML5What Lies Ahead for HTML5
What Lies Ahead for HTML5
Krzysztof Szafranek
 
Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...
Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...
Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...
Krzysztof Szafranek
 
Practical Guide to Unit Testing
Practical Guide to Unit TestingPractical Guide to Unit Testing
Practical Guide to Unit Testing
Krzysztof Szafranek
 
Productive JavaScript Workflow
Productive JavaScript WorkflowProductive JavaScript Workflow
Productive JavaScript Workflow
Krzysztof Szafranek
 
Box2Dweb
Box2DwebBox2Dweb
Radiant CMS - smart simplicity
Radiant CMS - smart simplicityRadiant CMS - smart simplicity
Radiant CMS - smart simplicity
Krzysztof Szafranek
 
Ruby, Amazon Web Services and You
Ruby, Amazon Web Services and YouRuby, Amazon Web Services and You
Ruby, Amazon Web Services and You
Krzysztof Szafranek
 

More from Krzysztof Szafranek (10)

Mobile Game Development
Mobile Game DevelopmentMobile Game Development
Mobile Game Development
 
ESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. NowESCMAScript 6: Get Ready For The Future. Now
ESCMAScript 6: Get Ready For The Future. Now
 
Getting the Most out of Your Tools
Getting the Most out of Your ToolsGetting the Most out of Your Tools
Getting the Most out of Your Tools
 
What Lies Ahead for HTML5
What Lies Ahead for HTML5What Lies Ahead for HTML5
What Lies Ahead for HTML5
 
Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...
Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...
Confessions of the Traitor: How Objective C Made Me a Better JavaScript Progr...
 
Practical Guide to Unit Testing
Practical Guide to Unit TestingPractical Guide to Unit Testing
Practical Guide to Unit Testing
 
Productive JavaScript Workflow
Productive JavaScript WorkflowProductive JavaScript Workflow
Productive JavaScript Workflow
 
Box2Dweb
Box2DwebBox2Dweb
Box2Dweb
 
Radiant CMS - smart simplicity
Radiant CMS - smart simplicityRadiant CMS - smart simplicity
Radiant CMS - smart simplicity
 
Ruby, Amazon Web Services and You
Ruby, Amazon Web Services and YouRuby, Amazon Web Services and You
Ruby, Amazon Web Services and You
 

Recently uploaded

GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
Sri Ambati
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
Dorra BARTAGUIZ
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
Kari Kakkonen
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
RTTS
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Albert Hoitingh
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
g2nightmarescribd
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
ThousandEyes
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
Laura Byrne
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Product School
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 

Recently uploaded (20)

GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
GenAISummit 2024 May 28 Sri Ambati Keynote: AGI Belongs to The Community in O...
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Elevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object CalisthenicsElevating Tactical DDD Patterns Through Object Calisthenics
Elevating Tactical DDD Patterns Through Object Calisthenics
 
DevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA ConnectDevOps and Testing slides at DASA Connect
DevOps and Testing slides at DASA Connect
 
JMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and GrafanaJMeter webinar - integration with InfluxDB and Grafana
JMeter webinar - integration with InfluxDB and Grafana
 
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdfFIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
FIDO Alliance Osaka Seminar: Passkeys at Amazon.pdf
 
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdfFIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
FIDO Alliance Osaka Seminar: The WebAuthn API and Discoverable Credentials.pdf
 
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
Encryption in Microsoft 365 - ExpertsLive Netherlands 2024
 
Generating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using SmithyGenerating a custom Ruby SDK for your web service or Rails API using Smithy
Generating a custom Ruby SDK for your web service or Rails API using Smithy
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
Assuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyesAssuring Contact Center Experiences for Your Customers With ThousandEyes
Assuring Contact Center Experiences for Your Customers With ThousandEyes
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
The Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and SalesThe Art of the Pitch: WordPress Relationships and Sales
The Art of the Pitch: WordPress Relationships and Sales
 
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdfFIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
FIDO Alliance Osaka Seminar: FIDO Security Aspects.pdf
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...Mission to Decommission: Importance of Decommissioning Products to Increase E...
Mission to Decommission: Importance of Decommissioning Products to Increase E...
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 

JavaScript Refactoring

  • 2. We form a wonderful community. Yet, we can learn a lot from other programming communities.
  • 4. Improving the design of code without changing its external behavior
  • 5. Refactoring is not... If the changes affect external behavior, it’s rewriting, not refactoring.
  • 6. Refactoring is not... For #1 excuse visit http://xkcd.com/303
  • 7. continuous small steps Refactoring should be done as a part of our every day workflow. Don’t wait for massive “big bang” refactorings.
  • 8. Investment When to refactor? It’s an investment: - Makes change easier. - Helps find bugs. But comes with time and effort cost.
  • 9. enables you to go faster May make little sense just before a deadline.
  • 10. makes code clear to other people Not machines
  • 11. 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
  • 12. ; It’s much more important to write code that will be easy to understand by other people than just understood by a browser.
  • 13. clarity vs performance
  • 14. clarity enables 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.
  • 16. Code is like cheese. Some people find smelly what other find deliciously wonderful.
  • 17. duplication It makes change harder. The rule of 3: the third time you copy something, it’s time to refactor.
  • 18. 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!
  • 19. switch/if statements When they’re long and complex.
  • 20. 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.
  • 21. comments Comments become bad when used as a deodorant to hide messy code.
  • 23. jslint jshint Static analysis tools that detect mistakes and enforce clear style. Using lint was the single most important boost to my productivity in writing JS
  • 24. John Carmack “Anything that isn’t crystal clear to a static analysis tool probably 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/
  • 26. UNIT TESTS Tests give a safety net. How else do you know that you didn’t change the behavior?
  • 27. JavaScript developer’s typical reaction to a question about unit tests
  • 29. 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.
  • 30. 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 { Real code, one method, ~150 lines. 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
  • 31. }; 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.
  • 32. 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.
  • 33. 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.
  • 34. 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 }); }
  • 35. 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.
  • 36. Remove speculative code switch (action) { case "move": break; case "destroy": break; default: break; }
  • 37. 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!
  • 38. 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.
  • 39. 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 + InfoMode.prototype.activate = function (config) { ' food in <span id="timeLeft">'+utils.formatTime(millisecondsLeft)+'</span></p>'; this.target = config.target; } else if (entity.is('ship')) { if(this.target.entity.contractState === "started") { var entity = this.target.entity; bulk = '<div class="progress"><div style="width: 0%;"></div></div><p>Repair complete in <span id="timeLeft">' + if (entity.is('castle') && wooga.castle.playerData.upgradingCastle) { utils.formatTime(millisecondsLeft) + '</span></p>'; } wooga.castle.CastleCompleteScreen.instance().show(); } this.deactivate(); this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC); } else { return; if(entity.is('castle')) { } if(wooga.castle.playerData.upgradingCastle) { wooga.castle.CastleCompleteScreen.instance().show(); if (entity.is('decoration')) { this.deactivate(); this.target.makeDynamic(); this.manager.setMode(wooga.castle.GameModesManager.Mode.BASIC); } return; } this.infoPanel.innerHTML = '<h1>' + entity.getProperName() + '</h1><div bulk = '<p><span class="population">Supported Population: ' + class=specification>' + entity.getInfoModeString() + '</div>'; entity.definition.population + '</span></p>'; } else if(entity.is('decoration')) { // RADAR: [szafranek] Why is this HERE? Moving it to worldView and listening to "entity/focused" looks better to me. bulk = '<p>Nearby buildings get a '; var concatBoosts = false; this.manager.view.isFocusedEntityView = function (entityView) { if (entity.definition.goldBoost) { return entityView === config.target; bulk += 'gold boost of ' + entity.definition.goldBoost + '%'; }; concatBoosts = true; } if (entity.definition.foodBoost) { if (entity.contractState === wooga.castle.House.ContractState.STARTED) { if(concatBoosts) { this.showProgressBar(entity.contractStartTime, bulk += '</p><p>and a '; } entity.contract.requiredTime); bulk += 'food boost of ' + entity.definition.foodBoost + '%.'; } else if (entity.contractState === } wooga.castle.House.ContractState.CONSTRUCTION) { } this.showProgressBar(entity.constructionStartTime, } entity.contract.constructionTime); } this.infoPanel.innerHTML = html.replace('{bulk}', bulk); this.manager.view.isFocusedEntityView = function (entityView) { utils.publish('view:entity/focused', { return entityView === config.target; "entity": entity, }; "entityView": entity.entityView, if(this.target.entity.contractState === "started") { "infoMode": this var progress = document.querySelector('.progress div'), }); timer = document.getElementById('timeLeft'); progress.style.width = Math.floor((((new Date()).getTime() - millisecondsStart) / millisecondsTotal) * 100) + "%"; this.showBoosts(entity); counter = setInterval(function () { var now = new Date().getTime(), timeFromStart = now - millisecondsStart; this.show(); 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(); Original method after refactoring. };
  • 40. Know where to stop. Ask yourself: is the further investment wortwhile?
  • 43. coderetreat.org Organize one yourself if there’s none in your city!
  • 44. 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
  • 45. Write code for people Learn from others @szafranek
  • 46. _gee_ fingersss chez loulou diathesis linder6580 Pipistrula ginza_line Ocial GDC superfluity Łukasz Bałamut mooong photo credits