Slide 1

Slide 1 text

@fed_goose Refactoring a Legacy Application with React Ali Orlando @fed_goose aporlando

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

@fed_goose Test coverage?

Slide 4

Slide 4 text

@fed_goose Changes → New Tests?

Slide 5

Slide 5 text

@fed_goose !

Slide 6

Slide 6 text

@fed_goose "

Slide 7

Slide 7 text

@fed_goose #

Slide 8

Slide 8 text

@fed_goose $

Slide 9

Slide 9 text

@fed_goose Legacy Application Characteristics • Low/No Test Coverage • Tests aren’t added with new changes • Changes are painful • Code is coupled & difficult to navigate • Application behavior is undocumented • Little confidence that changes won’t break your application

Slide 10

Slide 10 text

@fed_goose I’m Ali Orlando Front-end developer @ %

Slide 11

Slide 11 text

@fed_goose What we’ll cover…

Slide 12

Slide 12 text

@fed_goose & What we’ll cover…

Slide 13

Slide 13 text

@fed_goose What we’ll cover… ❤

Slide 14

Slide 14 text

@fed_goose What we’ll cover…

Slide 15

Slide 15 text

@fed_goose What we’ll cover…

Slide 16

Slide 16 text

@fed_goose What we’ll cover…

Slide 17

Slide 17 text

@fed_goose ( What we’ll cover…

Slide 18

Slide 18 text

@fed_goose What we’ll cover… • Why Refactor • Why OnShift chose React for refactoring • Example of refactoring a jQuery application with React • Pros & Cons of using Redux to manage state shared between frameworks • Example of using Redux • Additional lessons learned along the way

Slide 19

Slide 19 text

@fed_goose Why Refactor?

Slide 20

Slide 20 text

Martin Fowler

Slide 21

Slide 21 text

@fed_goose -Martin Fowler, “Refactoring: Improving the Design of Existing Code” “Refactoring is a controlled technique for improving the design of an existing code base. Its essence is applying a series of small behavior-preserving transformations… the cumulative effect of each of these transformations is quite significant. By doing them in small steps you reduce the risk of introducing errors… [and] avoid having the system broken while you are carrying out the restructuring - which allows you to gradually refactor a system over an extended period of time.” Why Refactor?

Slide 22

Slide 22 text

Why Refactor?

Slide 23

Slide 23 text

Why Refactor?

Slide 24

Slide 24 text

@fed_goose ) Why Refactor?

Slide 25

Slide 25 text

@fed_goose * Why Refactor?

Slide 26

Slide 26 text

@fed_goose * Why Refactor? * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Slide 27

Slide 27 text

@fed_goose + Why Refactor? ❓ ❓ ❓ ❓

Slide 28

Slide 28 text

Why Refactor?

Slide 29

Slide 29 text

@fed_goose → somePage.html Why Refactor?

Slide 30

Slide 30 text

@fed_goose <script src=“checkTheTime.js” /> <script src=“doABackflip.js” /> <script src=“errorMessage.js” /> <script src=“thatOneTimeAtCodemash.js” /> → somePage.html

Slide 31

Slide 31 text

@fed_goose <script src=“checkTheTime.js” /> <script src=“doABackflip.js” /> <script src=“errorMessage.js” /> <script src=“thatOneTimeAtCodemash.js” /> → $element.on(‘click’, doTheTwoPageLongFunction); → somePage.html

Slide 32

Slide 32 text

@fed_goose span

Slide 33

Slide 33 text

@fed_goose span.setMe

Slide 34

Slide 34 text

@fed_goose div > span.setMe

Slide 35

Slide 35 text

@fed_goose div > div > span.setMe

Slide 36

Slide 36 text

@fed_goose div#application > div > div > span.setMe

Slide 37

Slide 37 text

@fed_goose $(‘span.warning’)

Slide 38

Slide 38 text

@fed_goose $(‘span.warning’).show()

Slide 39

Slide 39 text

@fed_goose if($(‘div.doNotify’).length > 0 ) {
 $(‘span.warning’).show();
 }

Slide 40

Slide 40 text

@fed_goose + Why Refactor? ❓ ❓ ❓ ❓

Slide 41

Slide 41 text

@fed_goose technical debt Why Refactor? inevitable rework that comes from choosing a quick and easy solution to a problem instead of spending time to write a more extensible solution

Slide 42

Slide 42 text

No content

Slide 43

Slide 43 text

@fed_goose Rewrite?

Slide 44

Slide 44 text

@fed_goose ReWRONG*

Slide 45

Slide 45 text

@fed_goose The Case Against Rewriting the Application

Slide 46

Slide 46 text

Application Complexity Learn from your mistakes! The Case Against Rewriting the Application

Slide 47

Slide 47 text

@fed_goose –Joel Spolsky, “Things You Should Never Do, Part I” “Each of those bugs took weeks of real-world usage before they were found. The programmer might have spent a couple of days reproducing the bug in the lab and fixing it. If it’s like a lot of bugs, the fix might be one line of code, or it might even be a couple of characters, but a lot of work and time went into those two characters.” The Case Against Rewriting the Application

Slide 48

Slide 48 text

Application Complexity Learn from your mistakes! The Case Against Rewriting the Application

Slide 49

Slide 49 text

@fed_goose Maintenance & Resources The Case Against Rewriting the Application

Slide 50

Slide 50 text

@fed_goose Customer Satisfaction & User Experience The Case Against Rewriting the Application

Slide 51

Slide 51 text

@fed_goose - The Case Against Rewriting the Application

Slide 52

Slide 52 text

@fed_goose Customer Satisfaction & User Experience The Case Against Rewriting the Application

Slide 53

Slide 53 text

It doesn’t make cents

Slide 54

Slide 54 text

@fed_goose –Joel Spolsky, “Things You Should Never Do, Part I” “You are wasting an outlandish amount of money writing code that already exists.”

Slide 55

Slide 55 text

@fed_goose . / 0 The Case Against Rewriting the Application

Slide 56

Slide 56 text

@fed_goose The Case Against Rewriting the Application 1. Application Complexity - Learn from your mistakes! 2. Maintenance & Resources 3. Customer Satisfaction & User Experience

Slide 57

Slide 57 text

@fed_goose *terms and conditions may apply The Case Against Rewriting the Application

Slide 58

Slide 58 text

@fed_goose There are some things that rewrites can fix The Case Against Rewriting the Application For everyone else, there’s Refactoring

Slide 59

Slide 59 text

@fed_goose Ok, how?

Slide 60

Slide 60 text

@fed_goose Set Goals • Ease of on boarding developers? • Performance? • Reusability? • Maintainability? • Testability?

Slide 61

Slide 61 text

@fed_goose Create a plan

Slide 62

Slide 62 text

@fed_goose 1. Choose a technology Create a Plan

Slide 63

Slide 63 text

@fed_goose 2. Try it, find a pattern Create a Plan

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

@fed_goose 2. Try it, find a pattern Create a Plan

Slide 66

Slide 66 text

@fed_goose 3. Review & plan Create a Plan

Slide 67

Slide 67 text

@fed_goose Create a Plan 1. Choose a technology 2. Try it out, find a pattern 3. Review & plan

Slide 68

Slide 68 text

@fed_goose Create a Plan 1. Choose a technology 2. Try it out, find a pattern 3. Review & plan } Research

Slide 69

Slide 69 text

@fed_goose 4. Identify an opportunity Create a Plan

Slide 70

Slide 70 text

@fed_goose 5. Start small, grow over time Create a Plan

Slide 71

Slide 71 text

Create a Plan (Start small, grow over time)

Slide 72

Slide 72 text

@fed_goose Create a plan 1. Choose a technology 2. Try it out, find a pattern 3. Review & plan 4. Identify an opportunity 5. Start small & grow out over time

Slide 73

Slide 73 text

@fed_goose Once upon a time…

Slide 74

Slide 74 text

@fed_goose (in 2016)

Slide 75

Slide 75 text

@fed_goose

Slide 76

Slide 76 text

@fed_goose

Slide 77

Slide 77 text

M N A Y M N H O T S L T R A E

Slide 78

Slide 78 text

@fed_goose OnShift’s Refactor

Slide 79

Slide 79 text

@fed_goose OnShift’s Refactor

Slide 80

Slide 80 text

@fed_goose OnShift’s Refactor

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

@fed_goose Create a plan 1. Choose a technology 2. Try it out, find a pattern 3. Review & plan 4. Identify an opportunity 5. Start small & grow out over time

Slide 83

Slide 83 text

@fed_goose Why React?

Slide 84

Slide 84 text

@fed_goose Encapsulated Why React?

Slide 85

Slide 85 text

@fed_goose Why React? DOM Optimized

Slide 86

Slide 86 text

@fed_goose Why React? Testable

Slide 87

Slide 87 text

@fed_goose Why React? Documentation & Support

Slide 88

Slide 88 text

@fed_goose Why React? Domain Knowledge *mileage may vary

Slide 89

Slide 89 text

@fed_goose Why React? • Encapsulated • Declarative & Optimized • Testable • Documentation & Support • Domain Knowledge

Slide 90

Slide 90 text

@fed_goose Create a plan 1. Choose a technology 2. Try it out, find a pattern 3. Review & plan 4. Identify an opportunity 5. Start small & grow out over time

Slide 91

Slide 91 text

@fed_goose Create a plan 1. Choose a technology 2. Try it out, find a pattern 3. Review & plan 4. Identify an opportunity 5. Start small & grow out over time

Slide 92

Slide 92 text

@fed_goose Example github.com/aporlando/jquery-to-react

Slide 93

Slide 93 text

@fed_goose

Slide 94

Slide 94 text

@fed_goose 1 2 3-8 … 9 10
11

To Do List

12
    13
14 15 16 Add 17 18 19 Remove Completed 20 21
22 23 24 25 index.html

Slide 95

Slide 95 text

@fed_goose 1 2 3-8 … 9 10
11

To Do List

12
    13
14 15 16 Add 17 18 19 Remove Completed 20 21
22 23 24 25 index.html

Slide 96

Slide 96 text

@fed_goose 1 2 3-8 … 9 10
11

To Do List

12
    13
14 15 16 Add 17 18 19 Remove Completed 20 21
22 23 24 25 index.html

Slide 97

Slide 97 text

@fed_goose 1 2 3-8 … 9 10
11

To Do List

12
    13
14 15 16 Add 17 18 19 Remove Completed 20 21
22 23 24 25 index.html

Slide 98

Slide 98 text

@fed_goose 1 2 3-8 … 9 10
11

To Do List

12
    13
14 15 16 Add 17 18 19 Remove Completed 20 21
22 23 24 25 index.html

Slide 99

Slide 99 text

@fed_goose 1 // This exists to keep the checkbox & label in sync 2 var uniqueCounter = 0; 3 4 // template for the todo items 5 function todoCreator(todoText, completed) { 6 uniqueCounter = uniqueCounter + 1; 7 var todoId = 'todo' + uniqueCounter; 8 return '
  • ' + 9 '
    ' + 10 ' ' + 11 ' ' + 12 (completed ? '' + todoText + '' : todoText) + 13 ' ' + 14 '
    ' + 15 ' Delete' + 16 ‘
  • '; 17 } 18 19 // Add a todo to the list 20 function addTodo(todoText) { 21 var item = todoCreator(todoText); 22 $('#todos').append(item); 23 } 24 25 // Remove the todo entirely 26 function deleteTodo(todo) { 27 $(todo).parent().remove(); todo.js

    Slide 100

    Slide 100 text

    @fed_goose 1 // This exists to keep the checkbox & label in sync 2 var uniqueCounter = 0; 3 4 // template for the todo items 5 function todoCreator(todoText, completed) { 6 uniqueCounter = uniqueCounter + 1; 7 var todoId = 'todo' + uniqueCounter; 8 return '
  • ' + 9 '
    ' + 10 ' ' + 11 ' ' + 12 (completed ? '' + todoText + '' : todoText) + 13 ' ' + 14 '
    ' + 15 ' Delete' + 16 ‘
  • '; 17 } 18 19 // Add a todo to the list 20 function addTodo(todoText) { 21 var item = todoCreator(todoText); 22 $('#todos').append(item); 23 } 24 25 // Remove the todo entirely 26 function deleteTodo(todo) { 27 $(todo).parent().remove(); todo.js

    Slide 101

    Slide 101 text

    @fed_goose 12 (completed ? '' + todoText + '' : todoText) + 13 ' ' + 14 ' ' + 15 ' Delete' + 16 ‘'; 17 } 18 19 // Add a todo to the list 20 function addTodo(todoText) { 21 var item = todoCreator(todoText); 22 $('#todos').append(item); 23 } 24 25 // Remove the todo entirely 26 function deleteTodo(todo) { 27 $(todo).parent().remove(); 28 } 29 30 // Strike out the todo item when it is completed, remove strike when it is incomplete 31 function toggleComplete(todo) { 32 var label = $(todo).find('label'); 33 if ($(todo).find('input').prop('checked')) { 34 label.html('' + 35 label.text() + 36 ''); 37 } else { 38 label.html(label.text()); 39 } 40 } 41 42 function maybeHideDeleteAll() {

    Slide 102

    Slide 102 text

    @fed_goose 17 } 18 19 // Add a todo to the list 20 function addTodo(todoText) { 21 var item = todoCreator(todoText); 22 $('#todos').append(item); 23 } 24 25 // Remove the todo entirely 26 function deleteTodo(todo) { 27 $(todo).parent().remove(); 28 } 29 30 // Strike out the todo item when it is completed, remove strike when it is incomplete 31 function toggleComplete(todo) { 32 var label = $(todo).find('label'); 33 if ($(todo).find('input').prop('checked')) { 34 label.html('' + 35 label.text() + 36 ''); 37 } else { 38 label.html(label.text()); 39 } 40 } 41 42 function maybeHideDeleteAll() { 43 var completedItems = $('#todos input:checked').length; 44 if(completedItems > 0) { 45 $('#clearCompleted').show(); 46 } else { 47 $('#clearCompleted').hide(); 48 }

    Slide 103

    Slide 103 text

    @fed_goose 22 $('#todos').append(item); 23 } 24 25 // Remove the todo entirely 26 function deleteTodo(todo) { 27 $(todo).parent().remove(); 28 } 29 30 // Strike out the todo item when it is completed, remove strike when it is incomplete 31 function toggleComplete(todo) { 32 var label = $(todo).find('label'); 33 if ($(todo).find('input').prop('checked')) { 34 label.html('' + 35 label.text() + 36 ''); 37 } else { 38 label.html(label.text()); 39 } 40 } 41 42 function maybeHideDeleteAll() { 43 var completedItems = $('#todos input:checked').length; 44 if(completedItems > 0) { 45 $('#clearCompleted').show(); 46 } else { 47 $('#clearCompleted').hide(); 48 } 49 } 50 51 // Attach the DOM events once the page has loaded 52 $(document).ready(function() { 53 // When the form input is submitted, add the todo item

    Slide 104

    Slide 104 text

    @fed_goose 33 if ($(todo).find('input').prop('checked')) { 34 label.html('' + 35 label.text() + 36 ''); 37 } else { 38 label.html(label.text()); 39 } 40 } 41 42 function maybeHideDeleteAll() { 43 var completedItems = $('#todos input:checked').length; 44 if(completedItems > 0) { 45 $('#clearCompleted').show(); 46 } else { 47 $('#clearCompleted').hide(); 48 } 49 } 50 51 // Attach the DOM events once the page has loaded 52 $(document).ready(function() { 53 // When the form input is submitted, add the todo item 54 $("#addForm").on('submit', function(e) { 55 e.preventDefault(); 56 var input = $("input#todoInput"); 57 addTodo(input.val()); 58 input.val(""); 59 }); 60 61 // When Remove Completed button is clicked, remove all checked items from the DOM 62 $("#clearCompleted").on('click', function(e) { 63 e.preventDefault(e); 64 $('#todos input:checked').closest('li').remove();

    Slide 105

    Slide 105 text

    @fed_goose 43 var completedItems = $('#todos input:checked').length; 44 if(completedItems > 0) { 45 $('#clearCompleted').show(); 46 } else { 47 $('#clearCompleted').hide(); 48 } 49 } 50 51 // Attach the DOM events once the page has loaded 52 $(document).ready(function() { 53 // When the form input is submitted, add the todo item 54 $("#addForm").on('submit', function(e) { 55 e.preventDefault(); 56 var input = $("input#todoInput"); 57 addTodo(input.val()); 58 input.val(""); 59 }); 60 61 // When Remove Completed button is clicked, remove all checked items from the DOM 62 $("#clearCompleted").on('click', function(e) { 63 e.preventDefault(e); 64 $('#todos input:checked').closest('li').remove(); 65 $(this).hide(); 66 }); 67 }); 68

    Slide 106

    Slide 106 text

    @fed_goose

    Slide 107

    Slide 107 text

    @fed_goose Header

    Slide 108

    Slide 108 text

    @fed_goose Header To Do List

    Slide 109

    Slide 109 text

    @fed_goose Header To Do Item To Do List

    Slide 110

    Slide 110 text

    @fed_goose Header To Do Item To Do List Add Item Input

    Slide 111

    Slide 111 text

    @fed_goose Header To Do Item To Do List Add Item Input Remove Completed Button

    Slide 112

    Slide 112 text

    @fed_goose Add Item Input

    Slide 113

    Slide 113 text

    @fed_goose 1 2 3-8 9 10
    11

    To Do List

    12
      13
    14 15 16 Add 17 18 19 Remove Completed 20 21
    22 23 24 25 index.html

    Slide 114

    Slide 114 text

    @fed_goose

    Slide 115

    Slide 115 text

    @fed_goose

    Slide 116

    Slide 116 text

    @fed_goose 1 2 3-8 9 10
    11

    To Do List

    12
      13
    14 15 16 Add 17 18 19 Remove Completed 20 21
    22 23 24 25 26 27 28 index.html

    Slide 117

    Slide 117 text

    @fed_goose index.html

    Slide 118

    Slide 118 text

    @fed_goose 1 2 3-8 9 10
    11

    To Do List

    12
      13
    14 15 16 Add 17 18 19 Remove Completed 20 21
    22 23 24 </ script> 25 <script src="https://unpkg.com/[email protected]/babel.min.js"> 26 27 28 index.html

    Slide 119

    Slide 119 text

    @fed_goose class AddTodoInput extends React.Component { render() { return ( Add ); } } AddTodoInput.js

    Slide 120

    Slide 120 text

    @fed_goose class AddTodoInput extends React.Component { render() { return ( Add ); } } AddTodoInput.js

    Slide 121

    Slide 121 text

    @fed_goose 1 2 3-8 9 10
    11

    To Do List

    12
      13
    14 15 16 Add 17 18 19 Remove Completed 20 21
    22 23 24 25 26 27 28 index.html

    Slide 122

    Slide 122 text

    @fed_goose 1 2 3-8 9 10
    11

    To Do List

    12
      13
    14 15 16 Remove Completed 17 18
    19 20 21 22 23 24 25 26 index.html

    Slide 123

    Slide 123 text

    @fed_goose class AddTodoInput extends React.Component { render() { return ( Add ); } } AddTodoInput.js ReactDOM.render( , document.querySelector(‘[data-react-component="AddTodoInput"]') );

    Slide 124

    Slide 124 text

    @fed_goose $("#addForm").on('submit', function(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); }); todo.js class AddTodoInput extends React.Component { render() { return ( Add ); } } AddTodoInput.js

    Slide 125

    Slide 125 text

    @fed_goose

    Slide 126

    Slide 126 text

    @fed_goose $("#addForm").on('submit', function(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); }); todo.js class AddTodoInput extends React.Component { render() { return ( Add ); } } AddTodoInput.js

    Slide 127

    Slide 127 text

    @fed_goose $("#addForm").on('submit', function(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); }); todo.js class AddTodoInput extends React.Component { render() { return ( Add ); } } AddTodoInput.js

    Slide 128

    Slide 128 text

    @fed_goose class AddTodoInput extends React.Component { render() { return ( Add ); } } e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); AddTodoInput.js

    Slide 129

    Slide 129 text

    @fed_goose class AddTodoInput extends React.Component { handleSubmit(e) { } render() { return ( Add ); } } e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); AddTodoInput.js

    Slide 130

    Slide 130 text

    @fed_goose class AddTodoInput extends React.Component { handleSubmit(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); } render() { return ( Add ); } } AddTodoInput.js

    Slide 131

    Slide 131 text

    @fed_goose class AddTodoInput extends React.Component { handleSubmit(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); } render() { return ( Add ); } } AddTodoInput.js

    Slide 132

    Slide 132 text

    @fed_goose class AddTodoInput extends React.Component { handleSubmit(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); } render() { return ( Add ); } } AddTodoInput.js

    Slide 133

    Slide 133 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); } render() { return ( Add ); } } AddTodoInput.js

    Slide 134

    Slide 134 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); } render() { return ( Add ); } } AddTodoInput.js

    Slide 135

    Slide 135 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); } render() { return ( Add ); } } AddTodoInput.js

    Slide 136

    Slide 136 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); var input = $("input#todoInput"); addTodo(input.val()); input.val(""); } render() { return ( Add ); } } AddTodoInput.js

    Slide 137

    Slide 137 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); addTodo(this.state.text); this.setState({ text: '' }); } render() { return ( Add ); } } AddTodoInput.js

    Slide 138

    Slide 138 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); addTodo(this.state.text); this.setState({ text: '' }); } render() { return ( Add ); } } AddTodoInput.js

    Slide 139

    Slide 139 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); addTodo(this.state.text); this.setState({ text: '' }); } render() { return ( Add ); } } AddTodoInput.js

    Slide 140

    Slide 140 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); addTodo(this.state.text); this.setState({ text: '' }); } handleInput(e) { this.setState({ text: e.target.value }); } render() { return ( Add ); } } AddTodoInput.js

    Slide 141

    Slide 141 text

    @fed_goose class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); addTodo(this.state.text); this.setState({ text: '' }); } handleInput(e) { this.setState({ text: e.target.value }); } render() { return ( Add ); } } AddTodoInput.js

    Slide 142

    Slide 142 text

    @fed_goose AddTodoInput.js class AddTodoInput extends React.Component { constructor(props) { super(props); this.state = { text: '' }; } handleSubmit(e) { e.preventDefault(); addTodo(this.state.text); this.setState({ text: '' }); } handleInput(e) { this.setState({ text: e.target.value }); } render() { return ( Add ); } }

    Slide 143

    Slide 143 text

    No content

    Slide 144

    Slide 144 text

    No content

    Slide 145

    Slide 145 text

    @fed_goose class RemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } RemoveCompletedButtons.js

    Slide 146

    Slide 146 text

    @fed_goose class RemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } RemoveCompletedButtons.js

    Slide 147

    Slide 147 text

    @fed_goose class RemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } RemoveCompletedButtons.js

    Slide 148

    Slide 148 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 149

    Slide 149 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 150

    Slide 150 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 151

    Slide 151 text

    @fed_goose

    Slide 152

    Slide 152 text

    @fed_goose Redux

    Slide 153

    Slide 153 text

    Why Redux? View Header Body Model 1 Model 2

    Slide 154

    Slide 154 text

    Why Redux? View Header Body Model 1 Model 2

    Slide 155

    Slide 155 text

    @fed_goose Redux Principles

    Slide 156

    Slide 156 text

    @fed_goose 1. Single Source of Truth Redux Principles

    Slide 157

    Slide 157 text

    1. Single Source of Truth Redux Principles Application View Application State

    Slide 158

    Slide 158 text

    @fed_goose 2. State is read-only Redux Principles

    Slide 159

    Slide 159 text

    2. State is read-only Redux Principles { type: 'SOMETHING_HAPPENED', moreInformation: 'I like turtles’ }

    Slide 160

    Slide 160 text

    @fed_goose 3. Changes to state happen in pure functions Redux Principles

    Slide 161

    Slide 161 text

    3. Changes to state happen in pure functions Redux Principles function reducer(state = {}, action) { if (action.type = 'SOMETHING_HAPPENED') { return { moreInformation: action.moreInformation }; } return state; }

    Slide 162

    Slide 162 text

    @fed_goose Redux Principles 1. Single source of truth 2. State is read-only 3. Changes to state happen in pure functions

    Slide 163

    Slide 163 text

    Redux State

    Slide 164

    Slide 164 text

    Redux defines UI State

    Slide 165

    Slide 165 text

    Redux defines triggers/dispatches Actions UI State

    Slide 166

    Slide 166 text

    Redux defines sent to triggers/dispatches Reducer Actions UI State

    Slide 167

    Slide 167 text

    Redux defines updates sent to triggers/dispatches Reducer Actions UI State Store

    Slide 168

    Slide 168 text

    Redux contains defines updates sent to triggers/dispatches Reducer Actions UI State Store

    Slide 169

    Slide 169 text

    No content

    Slide 170

    Slide 170 text

    @fed_goose class RemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } RemoveCompletedButtons.js

    Slide 171

    Slide 171 text

    @fed_goose class RemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } RemoveCompletedButtons.js

    Slide 172

    Slide 172 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 173

    Slide 173 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 174

    Slide 174 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 175

    Slide 175 text

    @fed_goose // The initial state of our store const initialState = { hasCompletedItems: false }; Initial state

    Slide 176

    Slide 176 text

    @fed_goose { type: 'SET_HAS_COMPLETED_ITEMS', hasCompletedItems: hasCompletedItems } action

    Slide 177

    Slide 177 text

    @fed_goose function setHasCompletedItems(hasCompletedItems) { return { type: 'SET_HAS_COMPLETED_ITEMS', hasCompletedItems: hasCompletedItems }; } action

    Slide 178

    Slide 178 text

    @fed_goose const initialState = { hasCompletedItems: false }; function reducer(state = initialState, action) { if (action.type = 'SET_HAS_COMPLETED_ITEMS') { return { hasCompletedItems: action.hasCompletedItems }; } return state; } reducer

    Slide 179

    Slide 179 text

    @fed_goose // Create the store with the reducer var store = Redux.createStore(reducer); Create the Store

    Slide 180

    Slide 180 text

    @fed_goose class UnconnectedRemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } function mapStateToProps(state) { return { show: state.hasCompletedItems }; } var RemoveCompletedButton = ReactRedux.connect(mapStateToProps) (UnconnectedRemoveCompletedButton); ReactDOM.render( , document.querySelector('[data-react-component="RemoveCompletedButton"]') );

    Slide 181

    Slide 181 text

    @fed_goose class UnconnectedRemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } function mapStateToProps(state) { return { show: state.hasCompletedItems }; } var RemoveCompletedButton = ReactRedux.connect(mapStateToProps) (UnconnectedRemoveCompletedButton); ReactDOM.render( , document.querySelector('[data-react-component="RemoveCompletedButton"]') );

    Slide 182

    Slide 182 text

    @fed_goose class UnconnectedRemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } function mapStateToProps(state) { return { show: state.hasCompletedItems }; } var RemoveCompletedButton = ReactRedux.connect(mapStateToProps) (UnconnectedRemoveCompletedButton); ReactDOM.render( , document.querySelector('[data-react-component="RemoveCompletedButton"]') );

    Slide 183

    Slide 183 text

    @fed_goose class UnconnectedRemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } function mapStateToProps(state) { return { show: state.hasCompletedItems }; } var RemoveCompletedButton = ReactRedux.connect(mapStateToProps) (UnconnectedRemoveCompletedButton); ReactDOM.render( , document.querySelector('[data-react-component="RemoveCompletedButton"]') );

    Slide 184

    Slide 184 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 185

    Slide 185 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); ReactDOM.render( , document.querySelector( ‘[data-react-component="RemoveCompletedButton"]') ); }

    Slide 186

    Slide 186 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); store.dispatch(setHasCompletedItems(completedItems > 0)); }

    Slide 187

    Slide 187 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); store.dispatch(setHasCompletedItems(completedItems > 0)); }

    Slide 188

    Slide 188 text

    @fed_goose todo.js function removeCheckedItems() { $('#todos input:checked').closest('li').remove(); store.dispatch(setHasCompletedItems(completedItems > 0)); } { type: 'SET_HAS_COMPLETED_ITEMS', hasCompletedItems: completedItems > 0 }

    Slide 189

    Slide 189 text

    @fed_goose const initialState = { hasCompletedItems: false }; function reducer(state = initialState, action) { if (action.type = 'SET_HAS_COMPLETED_ITEMS') { return { hasCompletedItems: action.hasCompletedItems }; } return state; } reducer

    Slide 190

    Slide 190 text

    @fed_goose class UnconnectedRemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } function mapStateToProps(state) { return { show: state.hasCompletedItems }; } var RemoveCompletedButton = ReactRedux.connect(mapStateToProps) (UnconnectedRemoveCompletedButton); ReactDOM.render( , document.querySelector('[data-react-component="RemoveCompletedButton"]') );

    Slide 191

    Slide 191 text

    @fed_goose class UnconnectedRemoveCompletedButton extends React.Component { render() { if(this.props.show) { return ( Remove Completed ); } return null; } } function mapStateToProps(state) { return { show: state.hasCompletedItems }; } var RemoveCompletedButton = ReactRedux.connect(mapStateToProps) (UnconnectedRemoveCompletedButton); ReactDOM.render( , document.querySelector('[data-react-component="RemoveCompletedButton"]') );

    Slide 192

    Slide 192 text

    @fed_goose Redux Principles 1. Single source of truth 2. State is read-only 3. Changes to state happen in pure functions

    Slide 193

    Slide 193 text

    @fed_goose Do I really need Redux?

    Slide 194

    Slide 194 text

    @fed_goose Why Redux? • Boot from state persisted in browser local storage. • Trace user interactions • Maintain undo history • Optimistic updates • Robust development tooling • Encapsulated business logic

    Slide 195

    Slide 195 text

    @fed_goose Do I really need Redux?

    Slide 196

    Slide 196 text

    @fed_goose How did refactoring turn out for OnShift?

    Slide 197

    Slide 197 text

    @fed_goose Summary Adding React → Encapsulated,

    Slide 198

    Slide 198 text

    @fed_goose Summary React → Encapsulated, iterative refactors → Pay d

    Slide 199

    Slide 199 text

    @fed_goose Summary refactors → Pay down technical debt → Improve

    Slide 200

    Slide 200 text

    @fed_goose Summary debt → Improve readability & maintainability → Eas

    Slide 201

    Slide 201 text

    @fed_goose Summary nability → Easier to fix bugs & add features → Add

    Slide 202

    Slide 202 text

    @fed_goose Summary atures → Address customer requirements → Happ

    Slide 203

    Slide 203 text

    @fed_goose Summary r requirements → Happy customers

    Slide 204

    Slide 204 text

    @fed_goose Create a plan 1. Choose a technology 2. Try it out, find a pattern 3. Review & plan 4. Identify an opportunity 5. Start small & grow out over time

    Slide 205

    Slide 205 text

    @fed_goose Sources “Things You Should Never Do, Part I”, Joel Spolsky, https://www.joelonsoftware.com/2000/04/06/things- you-should-never-do-part-i/ “Refactoring: Improving the Design of Existing Code”, Martin Fowler “Refactor or Rewrite”, Marco, Rails Love, https://www.railslove.com/stories/refactor-or-rewrite “How To Work With Legacy Code Management Summary”, Marco https://speakerdeck.com/donschado/ how-to-work-with-legacy-code-management-summary “Don’t Rewrite, React”, Ryan Florence, React-Europe 2015, https://www.youtube.com/watch? v=BF58ZJ1ZQxY “Motivation”, Redux Documentation, https://redux.js.org/docs/introduction/Motivation.html “You Might not need Redux”, Dan Abramov, https://medium.com/@dan_abramov/you-might-not-need- redux-be46360cf367

    Slide 206

    Slide 206 text

    @fed_goose Acknowledgements

    Slide 207

    Slide 207 text

    @fed_goose Ilya Gotfryd Tech Lead at OnShift @ikg_agent

    Slide 208

    Slide 208 text

    @fed_goose Nick Caley *not actually a dog @spud_

    Slide 209

    Slide 209 text

    @fed_goose Thank you. github.com/aporlando/jquery-to-react Ali Orlando @fed_goose