SlideShare une entreprise Scribd logo
1  sur  51
Télécharger pour lire hors ligne
Refactoring to
 Unobtrusive
  Javascript
         Federico Galassi
   federico.galassi@gmail.com
    http://federico.galassi.net/
Separation of Concerns



 Keeping different
    aspects of an
application separate
Separation of Concerns


So that everyone can
focus on one thing
      at a time
Unobtrusive Javascript

   Techniques to
enforce separation
 of javascript from
    other web
   technologies
Web Technologies


   Html                 Content

   Css                Presentation

Javascript         Presentation Logic

Server side          Business Logic
Rules of the Game


1 Javascript stays in its own files
2 Files are affected only by
changes directly related to
presentation logic
Game Strategy


How do we play?
Code refactoring
is improving quality of
existing code without
changing its functional
       behavior
Game Strategy



No refactoring
without testing

• unit testing with jsTestDriver & friends
• minimal functional testing with selenium & friends
• mock the server by wrapping XMLHttpRequest
1 Round

                        Html
                                   You see an
<script>
        doSomething();
        // ... more code ...
                                 inline script
</script>
1 Bad Smell

                        Html




<script>
        doSomething();



                                         Hey, it’s
        // ... more code ...
</script>




                                    javascript in
                                        html
1 Refactoring:
Externalize Inline Script
 Html                                       Js




             <script>
                     doSomething();
                     // ... more code ...
             </script>
1 Refactoring:
                     Externalize Inline Script
                        Html                                  Js




<script src="myjavascript.js">
                                       doSomething();
</script>
                                       // ... more code ...
2 Round

                      Html
                                  You see an
<button
 onclick="refreshView();"/>
                               event handler
                                registration
    Refresh
</button>




                                  by element
                                   attribute
2 Bad Smell

                      Html




<button
 onclick="refreshView();"/>



                                        Hey, it’s
    Refresh
</button>




                                   javascript in
                                       html
2 Refactoring:
              Attribute Event to Dom Event
                  Html                                     Js




<button
                              onclick="refreshView();"/>

    Refresh
</button>
2 Refactoring:
                  Attribute Event to Dom Event
                           Html                                 Js



   <!-- add id to locate it -->      var btnrefresh =
   <button id="btnRefresh">          document.getElementById(
       Refresh                           "btnRefresh"
   </button>                         );

                                     btnrefresh.addEventListener(
                                         "click",
                                         refreshView,
                                         false
                                     );


<!-- loaded after DOM is built -->
    <script src="myjavascript.js">
    </script>
</body>
</html>
3 Round

                         Html

                                         You see a
                                     javascript link
<a

href="javascript:showCredits();">

Show Credits</a>
3 Bad Smell

                         Html



<a

href="javascript:showCredits();">




                                              Hey, it’s
Show Credits</a>




                                         javascript in
                                             html
3 Refactoring:
                   Javascript Link to Click Event
                       Html                                     Js



<a

href="">                            javascript:showCredits();

Show Credits</a>
3 Refactoring:
                    Javascript Link to Click Event
                           Html                                 Js

                                     var showcredits =
 <!-- add id to locate it -->
                                     document.getElementById(
 <a id="linkShowCredits"
                                         "linkShowCredits"
 href="#">                           );

 Show Credits</a>
                                     // in refreshView you should
                                     // event.preventDefault
                                     showcredits.addEventListener(
                                         "click",
                                         refreshView,
                                         false
                                     );


<!-- loaded after DOM is built -->
    <script src="myjavascript.js">
    </script>
</body>
</html>
Game Break



Now HTML should
be Javascript free
4 Round

                               Js
                                          You see
div.onclick = function(e) {

    // div has been selected
                                     presentation
                                              set by
    var clicked = this;
    clicked.style.border =
        "1px solid blue";




                                     element.style
}




                                      properties
4 Bad Smell

                               Js



div.onclick = function(e) {

    // div has been selected



                                              Hey, it’s
    var clicked = this;
    clicked.style.border =
        "1px solid blue";




                                              css in
}




                                           javascript
4 Refactoring:
                  Dynamic Style to Css Class
                               Js                            Css



div.onclick = function(e) {

    // div has been selected
    var clicked = this;
                                    clicked.style.border =
                                        "1px solid blue";

}
4 Refactoring:
                  Dynamic Style to Css Class
                               Js                          Css



div.onclick = function(e) {

    // div has been selected
    var clicked = this;
                                    .selected: {
    // should be addClass
                                        border: 1px solid blue;
    clicked.setAttribute(
                                    }
        "class",
        "selected"
    );
}
5 Round

                              Js         You test a
var account = JSON.parse(
                                          complex
                                          boolean
    response
);
if (account.balance < 0) {




                                         expression
    show("can’t transfer money!");

}




                                        which is not
                                        presentation
5 Bad Smell

                                 Js



var account = JSON.parse(
    response
);




                                                 Hey, it’s
    if (account.balance < 0) {

      show("can’t transfer money!");

}



                                          business logic
                                           in javascript
5 Refactoring:
                     Business Logic Simple Test
                              Js                           Server



var account = JSON.parse(
    response
);
 if () {                             account.balance < 0

    show("can’t transfer money!");

}
5 Refactoring:
                     Business Logic Simple Test
                              Js                              Server



var account = JSON.parse(
    response
                                     <?php
);
                                        // use business logic to decide
 if (account.canTransfer) {             $account["canTransfer"] = false;
                                        echo json_encode($account);
    show("can’t transfer money!");   ?>

}
6 Round

                                     Js


// add book to the list
var book = doc.createElement("li");
                                              You see
                                             complex
var title = doc.createElement("strong");
titletext = doc.createTextNode(name);
title.appendChild(titletext);
var cover = doc.createElement("img");



                                           dom code to
cover.src = url;
book.appendChild(cover);
book.appendChild(title);
bookList.appendChild(book);



                                           generate html
6 Bad Smell

                                     Js


// add book to the list

var book = doc.createElement("li");
var title = doc.createElement("strong");
titletext = doc.createTextNode(name);



                                              Hey, it’s
title.appendChild(titletext);
var cover = doc.createElement("img");
cover.src = coverurl;
book.appendChild(cover);




                                              html in
book.appendChild(title);
bookList.appendChild(book);




                                           javascript
6 Refactoring:
                Dom Creation to Html Template
                          Js                                      Html


// add book to the list

                                 var book = doc.createElement("li");
                                 var title = doc.createElement("strong");
                                 titletext = doc.createTextNode(name);
                                 title.appendChild(titletext);
                                 var cover = doc.createElement("img");
                                 cover.src = coverurl;
                                 book.appendChild(cover);
                                 book.appendChild(title);
                                 bookList.appendChild(book);
6 Refactoring:
                 Dom Creation to Html Template
                                  Js                                Html


// add book to the list

var tplBook = loadTemplate(
    "book_tpl.html"
                                       <li>
);
                                           <strong>Title</strong>
var book = tplBook.substitute({
                                           <img src="Cover" />
    Title: name,
                                       </li>
    Cover: coverurl
});
bookList.appendChild(book);
Game Extra Time



Make javascript
 play well with
other javascript
7 Round

                       Js
var counter = 0;
// ... more code ...




                              You see code
                             placed outside
                               a function
7 Bad Smell

                         Js
var counter = 0;
// ... more code ...



// ... later ...
// counter is 1




                                     Hey, it’s a
                   Other Js
// redeclares previous
// counter !!



                                  global variable
var counter = 1;
7 Refactoring:
                         Global Abatement
                         Js
var counter = 0;
// ... more code ...



// ... later ...
// counter is 1
                                Using the
                              Module pattern
                   Other Js
// redeclares previous
                              we can make it
                                 private
// counter !!
var counter = 1;
7 Refactoring:
                            Global Abatement


                                  Wrap code in
(function() {
                            Js
    var counter = 0;
    // ... more code ...



    // ... later ...
    // counter is still 0
 })();
                                 an anonymous
                     Other Js    function which
                                  is immediately
    // don’t see previous
    // counter
    var counter = 1;




                                       invoked
8 Round
                        Login Js
btnLogin.onclick = function(e){
    login();
    toolbar.update();
    logger.log("login!");
                                      You see an
                                   event handler
}




function update() {
    // ...
                      Toolbar Js
                                     which calls
                                   many unrelated
}




                       Logger Js
function log(msg) {

}
    // ...
                                       modules
8 Bad Smell
                        Login Js
btnLogin.onclick = function(e){
    login();
    toolbar.update();
    logger.log("login!");
}




                      Toolbar Js
function update() {



                                         Hey, it’s
    // ...
}




function log(msg) {
                       Logger Js
                                      other modules
                                        javascript
    // ...
}
8 Impact
                        Login Js
btnLogin.onclick = function(e){
    login();
    toolbar.update();
    logger.log("login!");
}


     FAIL
                      Toolbar Js
function update() {



                                    Time coupling
    // ...
}




function log(msg) {
                       Logger Js
                                              issues
  t initialized
    // ...


No
}
8 Impact
                        Login Js
btnLogin.onclick = function(e){
    login();
    toolbar.update();
    logger.log("login!");



       hange
    friends.notify("login");



  eds C
}


Ne
                      Toolbar Js
function update() {
    // ...                        Friends   Js


                                                 Divergent
}
             function notify(event) {
                 // ...


                            dded
             }

                           A
                       Logger Js
function log(msg) {

}
    // ...
                                                  change
8 Refactoring:
                                       Custom Events
                            Login Js


                                          Custom events
btnLogin.onclick = function(e){
    login();




                                              invert
}




function update() {
    toolbar.update();
                        Toolbar Js
                                           dependency
                                            and make
}




                                          code readable
                         Logger Js
function log(msg) {
    logger.log("login!");
}
8 Refactoring:
                                      Custom Events
                           Login Js
 btnLogin.onclick = function(e){
     login();
     event.fire("login");                   Fire an high
                                         level custom
 }




                     Toolbar Js
function update() {...}
event.listen("login", function(e) {
    update();
                                        event and make
                                        other modules
});



                          Logger Js


                                           listen to it
function log(msg) {...}
event.listen("login", function(e) {
    log("login attempt");
});
9 Round

                               Js


// home getElementById "tabHome"
// news getElementById "tabNews"
// about getElementById "tabAbout"
                                       You see many
home.onclick = function() {

}
    showPage("pageHome");

news.onclick = function() {
                                      similar event
                                        handlers
    showPage("pageNews");
}
about.onclick = function() {
    showPage("pageAbout");
}
9 Bad Smell

                               Js


// home getElementById "tabHome"
// news getElementById "tabNews"
// about getElementById "tabAbout"

home.onclick = function() {
    showPage("pageHome");
}



                                               Hey, it’s
news.onclick = function() {
    showPage("pageNews");
}
about.onclick = function() {




                                            duplicated
    showPage("pageAbout");
}




                                            javascript
9 Impact

                                  Js


 // home getElementById "tabHome"
 // news getElementById "tabNews"
 // about getElementById "tabAbout"

 home.onclick = function() {

 }
     showPage("pageHome");                More tabs
                                          more code
 news.onclick = function() {
     showPage("pageNews");
 }
 about.onclick = function() {




                                         more handlers
     showPage("pageAbout");
 }
 contact.onclick = function() {
     showPage("pageContact");
 }



Needs Change                             more memory
                                            usage
9 Impact

                               Js


// home getElementById "tabHome"




                                       Need to track
// news getElementById "tabNews"
// about getElementById "tabAbout"

home.onclick = function() {
    showPage("pageHome");




                                     if new elements
}
news.onclick = function() {
    showPage("pageNews");
}
about.onclick = function() {



                                        are added to
    showPage("pageAbout");
}




                    Contact Js
tabContainer.addChild(
    "tabContact"
                                     register handlers
);


Missing click handler
9 Refactoring:
                               Events Delegation
                               Js
                                     Event delegation
                                       makes code
// home getElementById "tabHome"
// news getElementById "tabNews"
// about getElementById "tabAbout"

home.onclick = function() {



                                     more compact
    showPage("pageHome");
}
news.onclick = function() {
    showPage("pageNews");
}



                                           and
about.onclick = function() {
    showPage("pageAbout");
}




                                      maintainable
9 Refactoring:
                              Events Delegation


                                    Handle the event
                              Js




                                    in an elements
// container getElementById
// "tabContainer"

container.onclick = function(e) {




                                       ancestor.
    var id = e.target.id
    var page = id.replace(
        "tab", "page"
    );
    showPage(page);




                                    Bubbling makes
}




                                         it work
Game Over

Separation of concerns

Contenu connexe

Plus de Federico Galassi

CouchApps: Requiem for Accidental Complexity
CouchApps: Requiem for Accidental ComplexityCouchApps: Requiem for Accidental Complexity
CouchApps: Requiem for Accidental ComplexityFederico Galassi
 
Please Don't Touch the Slow Parts V3
Please Don't Touch the Slow Parts V3Please Don't Touch the Slow Parts V3
Please Don't Touch the Slow Parts V3Federico Galassi
 
Please Don't Touch the Slow Parts V2
Please Don't Touch the Slow Parts V2Please Don't Touch the Slow Parts V2
Please Don't Touch the Slow Parts V2Federico Galassi
 
Please Don't Touch the Slow Parts
Please Don't Touch the Slow PartsPlease Don't Touch the Slow Parts
Please Don't Touch the Slow PartsFederico Galassi
 
Javascript The Good Parts v2
Javascript The Good Parts v2Javascript The Good Parts v2
Javascript The Good Parts v2Federico Galassi
 

Plus de Federico Galassi (8)

CouchApps: Requiem for Accidental Complexity
CouchApps: Requiem for Accidental ComplexityCouchApps: Requiem for Accidental Complexity
CouchApps: Requiem for Accidental Complexity
 
Please Don't Touch the Slow Parts V3
Please Don't Touch the Slow Parts V3Please Don't Touch the Slow Parts V3
Please Don't Touch the Slow Parts V3
 
Javascript the New Parts
Javascript the New PartsJavascript the New Parts
Javascript the New Parts
 
Event Driven Javascript
Event Driven JavascriptEvent Driven Javascript
Event Driven Javascript
 
Please Don't Touch the Slow Parts V2
Please Don't Touch the Slow Parts V2Please Don't Touch the Slow Parts V2
Please Don't Touch the Slow Parts V2
 
Please Don't Touch the Slow Parts
Please Don't Touch the Slow PartsPlease Don't Touch the Slow Parts
Please Don't Touch the Slow Parts
 
Javascript The Good Parts v2
Javascript The Good Parts v2Javascript The Good Parts v2
Javascript The Good Parts v2
 
Javascript The Good Parts
Javascript The Good PartsJavascript The Good Parts
Javascript The Good Parts
 

Dernier

Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Paola De la Torre
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptxLBM Solutions
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAndikSusilo4
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 

Dernier (20)

Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Pigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping ElbowsPigging Solutions Piggable Sweeping Elbows
Pigging Solutions Piggable Sweeping Elbows
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101Salesforce Community Group Quito, Salesforce 101
Salesforce Community Group Quito, Salesforce 101
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Key Features Of Token Development (1).pptx
Key  Features Of Token  Development (1).pptxKey  Features Of Token  Development (1).pptx
Key Features Of Token Development (1).pptx
 
Azure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & ApplicationAzure Monitor & Application Insight to monitor Infrastructure & Application
Azure Monitor & Application Insight to monitor Infrastructure & Application
 
Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
#StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 

Refactoring to Unobtrusive Javascript

  • 1. Refactoring to Unobtrusive Javascript Federico Galassi federico.galassi@gmail.com http://federico.galassi.net/
  • 2. Separation of Concerns Keeping different aspects of an application separate
  • 3. Separation of Concerns So that everyone can focus on one thing at a time
  • 4. Unobtrusive Javascript Techniques to enforce separation of javascript from other web technologies
  • 5. Web Technologies Html Content Css Presentation Javascript Presentation Logic Server side Business Logic
  • 6. Rules of the Game 1 Javascript stays in its own files 2 Files are affected only by changes directly related to presentation logic
  • 7. Game Strategy How do we play? Code refactoring is improving quality of existing code without changing its functional behavior
  • 8. Game Strategy No refactoring without testing • unit testing with jsTestDriver & friends • minimal functional testing with selenium & friends • mock the server by wrapping XMLHttpRequest
  • 9. 1 Round Html You see an <script> doSomething(); // ... more code ... inline script </script>
  • 10. 1 Bad Smell Html <script> doSomething(); Hey, it’s // ... more code ... </script> javascript in html
  • 11. 1 Refactoring: Externalize Inline Script Html Js <script> doSomething(); // ... more code ... </script>
  • 12. 1 Refactoring: Externalize Inline Script Html Js <script src="myjavascript.js"> doSomething(); </script> // ... more code ...
  • 13. 2 Round Html You see an <button onclick="refreshView();"/> event handler registration Refresh </button> by element attribute
  • 14. 2 Bad Smell Html <button onclick="refreshView();"/> Hey, it’s Refresh </button> javascript in html
  • 15. 2 Refactoring: Attribute Event to Dom Event Html Js <button onclick="refreshView();"/> Refresh </button>
  • 16. 2 Refactoring: Attribute Event to Dom Event Html Js <!-- add id to locate it --> var btnrefresh = <button id="btnRefresh"> document.getElementById( Refresh "btnRefresh" </button> ); btnrefresh.addEventListener( "click", refreshView, false ); <!-- loaded after DOM is built --> <script src="myjavascript.js"> </script> </body> </html>
  • 17. 3 Round Html You see a javascript link <a href="javascript:showCredits();"> Show Credits</a>
  • 18. 3 Bad Smell Html <a href="javascript:showCredits();"> Hey, it’s Show Credits</a> javascript in html
  • 19. 3 Refactoring: Javascript Link to Click Event Html Js <a href=""> javascript:showCredits(); Show Credits</a>
  • 20. 3 Refactoring: Javascript Link to Click Event Html Js var showcredits = <!-- add id to locate it --> document.getElementById( <a id="linkShowCredits" "linkShowCredits" href="#"> ); Show Credits</a> // in refreshView you should // event.preventDefault showcredits.addEventListener( "click", refreshView, false ); <!-- loaded after DOM is built --> <script src="myjavascript.js"> </script> </body> </html>
  • 21. Game Break Now HTML should be Javascript free
  • 22. 4 Round Js You see div.onclick = function(e) { // div has been selected presentation set by var clicked = this; clicked.style.border = "1px solid blue"; element.style } properties
  • 23. 4 Bad Smell Js div.onclick = function(e) { // div has been selected Hey, it’s var clicked = this; clicked.style.border = "1px solid blue"; css in } javascript
  • 24. 4 Refactoring: Dynamic Style to Css Class Js Css div.onclick = function(e) { // div has been selected var clicked = this; clicked.style.border = "1px solid blue"; }
  • 25. 4 Refactoring: Dynamic Style to Css Class Js Css div.onclick = function(e) { // div has been selected var clicked = this; .selected: { // should be addClass border: 1px solid blue; clicked.setAttribute( } "class", "selected" ); }
  • 26. 5 Round Js You test a var account = JSON.parse( complex boolean response ); if (account.balance < 0) { expression show("can’t transfer money!"); } which is not presentation
  • 27. 5 Bad Smell Js var account = JSON.parse( response ); Hey, it’s if (account.balance < 0) { show("can’t transfer money!"); } business logic in javascript
  • 28. 5 Refactoring: Business Logic Simple Test Js Server var account = JSON.parse( response ); if () { account.balance < 0 show("can’t transfer money!"); }
  • 29. 5 Refactoring: Business Logic Simple Test Js Server var account = JSON.parse( response <?php ); // use business logic to decide if (account.canTransfer) { $account["canTransfer"] = false; echo json_encode($account); show("can’t transfer money!"); ?> }
  • 30. 6 Round Js // add book to the list var book = doc.createElement("li"); You see complex var title = doc.createElement("strong"); titletext = doc.createTextNode(name); title.appendChild(titletext); var cover = doc.createElement("img"); dom code to cover.src = url; book.appendChild(cover); book.appendChild(title); bookList.appendChild(book); generate html
  • 31. 6 Bad Smell Js // add book to the list var book = doc.createElement("li"); var title = doc.createElement("strong"); titletext = doc.createTextNode(name); Hey, it’s title.appendChild(titletext); var cover = doc.createElement("img"); cover.src = coverurl; book.appendChild(cover); html in book.appendChild(title); bookList.appendChild(book); javascript
  • 32. 6 Refactoring: Dom Creation to Html Template Js Html // add book to the list var book = doc.createElement("li"); var title = doc.createElement("strong"); titletext = doc.createTextNode(name); title.appendChild(titletext); var cover = doc.createElement("img"); cover.src = coverurl; book.appendChild(cover); book.appendChild(title); bookList.appendChild(book);
  • 33. 6 Refactoring: Dom Creation to Html Template Js Html // add book to the list var tplBook = loadTemplate( "book_tpl.html" <li> ); <strong>Title</strong> var book = tplBook.substitute({ <img src="Cover" /> Title: name, </li> Cover: coverurl }); bookList.appendChild(book);
  • 34. Game Extra Time Make javascript play well with other javascript
  • 35. 7 Round Js var counter = 0; // ... more code ... You see code placed outside a function
  • 36. 7 Bad Smell Js var counter = 0; // ... more code ... // ... later ... // counter is 1 Hey, it’s a Other Js // redeclares previous // counter !! global variable var counter = 1;
  • 37. 7 Refactoring: Global Abatement Js var counter = 0; // ... more code ... // ... later ... // counter is 1 Using the Module pattern Other Js // redeclares previous we can make it private // counter !! var counter = 1;
  • 38. 7 Refactoring: Global Abatement Wrap code in (function() { Js var counter = 0; // ... more code ... // ... later ... // counter is still 0 })(); an anonymous Other Js function which is immediately // don’t see previous // counter var counter = 1; invoked
  • 39. 8 Round Login Js btnLogin.onclick = function(e){ login(); toolbar.update(); logger.log("login!"); You see an event handler } function update() { // ... Toolbar Js which calls many unrelated } Logger Js function log(msg) { } // ... modules
  • 40. 8 Bad Smell Login Js btnLogin.onclick = function(e){ login(); toolbar.update(); logger.log("login!"); } Toolbar Js function update() { Hey, it’s // ... } function log(msg) { Logger Js other modules javascript // ... }
  • 41. 8 Impact Login Js btnLogin.onclick = function(e){ login(); toolbar.update(); logger.log("login!"); } FAIL Toolbar Js function update() { Time coupling // ... } function log(msg) { Logger Js issues t initialized // ... No }
  • 42. 8 Impact Login Js btnLogin.onclick = function(e){ login(); toolbar.update(); logger.log("login!"); hange friends.notify("login"); eds C } Ne Toolbar Js function update() { // ... Friends Js Divergent } function notify(event) { // ... dded } A Logger Js function log(msg) { } // ... change
  • 43. 8 Refactoring: Custom Events Login Js Custom events btnLogin.onclick = function(e){ login(); invert } function update() { toolbar.update(); Toolbar Js dependency and make } code readable Logger Js function log(msg) { logger.log("login!"); }
  • 44. 8 Refactoring: Custom Events Login Js btnLogin.onclick = function(e){ login(); event.fire("login"); Fire an high level custom } Toolbar Js function update() {...} event.listen("login", function(e) { update(); event and make other modules }); Logger Js listen to it function log(msg) {...} event.listen("login", function(e) { log("login attempt"); });
  • 45. 9 Round Js // home getElementById "tabHome" // news getElementById "tabNews" // about getElementById "tabAbout" You see many home.onclick = function() { } showPage("pageHome"); news.onclick = function() { similar event handlers showPage("pageNews"); } about.onclick = function() { showPage("pageAbout"); }
  • 46. 9 Bad Smell Js // home getElementById "tabHome" // news getElementById "tabNews" // about getElementById "tabAbout" home.onclick = function() { showPage("pageHome"); } Hey, it’s news.onclick = function() { showPage("pageNews"); } about.onclick = function() { duplicated showPage("pageAbout"); } javascript
  • 47. 9 Impact Js // home getElementById "tabHome" // news getElementById "tabNews" // about getElementById "tabAbout" home.onclick = function() { } showPage("pageHome"); More tabs more code news.onclick = function() { showPage("pageNews"); } about.onclick = function() { more handlers showPage("pageAbout"); } contact.onclick = function() { showPage("pageContact"); } Needs Change more memory usage
  • 48. 9 Impact Js // home getElementById "tabHome" Need to track // news getElementById "tabNews" // about getElementById "tabAbout" home.onclick = function() { showPage("pageHome"); if new elements } news.onclick = function() { showPage("pageNews"); } about.onclick = function() { are added to showPage("pageAbout"); } Contact Js tabContainer.addChild( "tabContact" register handlers ); Missing click handler
  • 49. 9 Refactoring: Events Delegation Js Event delegation makes code // home getElementById "tabHome" // news getElementById "tabNews" // about getElementById "tabAbout" home.onclick = function() { more compact showPage("pageHome"); } news.onclick = function() { showPage("pageNews"); } and about.onclick = function() { showPage("pageAbout"); } maintainable
  • 50. 9 Refactoring: Events Delegation Handle the event Js in an elements // container getElementById // "tabContainer" container.onclick = function(e) { ancestor. var id = e.target.id var page = id.replace( "tab", "page" ); showPage(page); Bubbling makes } it work