When a developer comes into an existing code base the urge to refactor can be overwhelming. However, legacy code bases – even those created and maintained with the best intentions – often resemble living organisms more than modular machines. Rather than simply taking out a module and replacing it with a better one, we have to surgically slice intricately connected sections of a code base apart and precisely tie each one off to prevent it from bleeding into another section. We also have to operate with the fear that a change in one part of a system may adversely affect other parts or even kill a critical piece of our application or infrastructure. This talk will teach you how to recognize the difference between necessary and cosmetic refactoring and how to assess and evaluate the risks of each. You will also walk away knowing how to develop safeguards and bypasses to minimize potential harm before, during, and after a refactor, as well as how to recognize the point of no return when rolling back a refactoring is riskier than keeping it in production. Maintaining a code base means you must constantly juggle the wish to improve it through refactoring and the potential side effects – you will walk away from this talk with clear techniques to help you find and maintain this balance.
3. First Do No Harm: Surgical Refactoring @nellshamrell
Refactoring is a change
and changes can go wrong
What is refactoring?
4. But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
5. But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
Software is being integrated into…
6. But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
Software is being integrated into…
Transportation
7. But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
Software is being integrated into…
Transportation
Energy sources
8. But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
Software is being integrated into…
Transportation
Energy sources
Medical Devices
10. So…is refactoring bad, then?
First Do No Harm: Surgical Refactoring @nellshamrell
Refactoring is neither inherently good OR bad
11. So…is refactoring bad, then?
First Do No Harm: Surgical Refactoring @nellshamrell
How you do it is what matters
12. How should I refactor?
First Do No Harm: Surgical Refactoring @nellshamrell
2 Common Approaches
13. How should I refactor?
First Do No Harm: Surgical Refactoring @nellshamrell
2 Common Approaches
1) Edit and Pray
14. How should I refactor?
First Do No Harm: Surgical Refactoring @nellshamrell
2 Common Approaches
1) Edit and Pray
2) Cover and Modify
15. How should I refactor?
First Do No Harm: Surgical Refactoring @nellshamrell
2 Common Approaches
1) Edit and Pray
2) Cover and Modify
- “Working Effectively with Legacy Code”
17. What is surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Change exactly what we INTEND to change
And ONLY what we intend to change
18. What is surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
First do no harm!
19. First Do No Harm: Surgical Refactoring @nellshamrell
Surgical refactoring is a series of
good habits that reduce risk
What is surgical refactoring?
20. First Do No Harm: Surgical Refactoring @nellshamrell
2 categories of refactoring
What is surgical refactoring?
21. First Do No Harm: Surgical Refactoring @nellshamrell
2 categories of refactoring
What is surgical refactoring?
1) Necessary refactoring
22. First Do No Harm: Surgical Refactoring @nellshamrell
2 categories of refactoring
What is surgical refactoring?
1) Necessary refactoring
2) Cosmetic refactoring
23. What is a necessary refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to add something
24. What is a necessary refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to add something
Code is too inefficient
25. What is a necessary refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to add something
Code is too inefficient
Blocked from achieving a business need
26. What is a necessary refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Necessary refactorings have a
moderate to high risk tolerance
27. What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
28. What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
No business need to change code
29. What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Something about it just bugs us
No business need to change code
30. What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Cosmetic refactorings
have a low risk tolerance
31. What about whitespace refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
32. What about whitespace refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Ultimate cosmetic refactoring
33. What about whitespace refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Ultimate cosmetic refactoring
Get a style guide
(i.e. Github style guide)
34. What about whitespace refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Ultimate cosmetic refactoring
Get a style guide
(i.e. Github style guide)
If whitespace does not violate style
guide, leave it alone!
35. What’s involved in surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
36. What’s involved in surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Pre-op: what to do before touching the code
37. What’s involved in surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Pre-op: what to do before touching the code
2) Operation: doing the actual refactoring
38. What’s involved in surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Pre-op: what to do before touching the code
2) Operation: doing the actual refactoring
3) Recovery: verifying the refactor
39. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Thanks, @mikelorant!
41. What is involved in pre-op?
First Do No Harm: Surgical Refactoring @nellshamrell
Diagnosis
(What exactly does the code do?)
42. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
43. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end Calls Ruby’s system method
44. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Executes sed command with
some flags
45. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Performs a substitution
46. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
In a series directories and files
47. So…do we know what it does?
First Do No Harm: Surgical Refactoring @nellshamrell
48. So…do we know what it does?
First Do No Harm: Surgical Refactoring @nellshamrell
Map is influenced by our own
experiences and expectations
49. So…do we know what it does?
First Do No Harm: Surgical Refactoring @nellshamrell
Only definite way of knowing what the code
does is to execute the code itself
50. So…do we know what it does?
First Do No Harm: Surgical Refactoring @nellshamrell
Best way to repeatedly execute the
code is through automated tests
51. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Now what does this
system call do?
52. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:do_system_things) { DoSystemThings.new }
Instantiate the class
53. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:do_system_things) { DoSystemThings.new }
let(:dir) { ‘something’ }
Sample argument
to pass to class
54. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:do_system_things) { DoSystemThings.new }
let(:dir) { ‘something’ }
describe ‘making the system call’ do
it ‘calls the Ruby#system method’ do
end
end
55. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:do_system_things) { DoSystemThings.new }
let(:dir) { ‘something’ }
describe ‘making the system call’ do
it ‘calls the Ruby#system method’ do
expect(do_system_things)
.to receive(:system).with(anything())
end
end
Expect that our instance
of the class
56. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
Will receive a system call
with any args
let(:do_system_things) { DoSystemThings.new }
let(:dir) { ‘something’ }
describe ‘making the system call’ do
it ‘calls the Ruby#system method’ do
expect(do_system_things)
.to receive(:system).with(anything())
end
end
57. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:do_system_things) { DoSystemThings.new }
let(:dir) { ‘something’ }
describe ‘making the system call’ do
it ‘calls the Ruby#system method’ do
expect(do_system_things)
.to receive(:system).with(anything())
do_system_things.do_the_thing(dir)
end
end
Call the method
58. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:do_system_things) { DoSystemThings.new }
let(:dir) { ‘something’ }
describe ‘making the system call’ do
it ‘calls the Ruby#system method’ do
expect(do_system_things)
.to receive(:system).with(anything())
do_system_things.do_the_thing(dir)
end
end
Spec Passes!
59. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
"sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Remove the system call
60. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
"sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Spec Fails!
61. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Put the system call back
62. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Spec Passes!
63. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
What return is expected?
64. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end Rdocs: system call returns true
when the command executes
successfully
65. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:dir) { ‘something’ }
context ‘when the method call is successful’ do
it ‘returns true’ do
end
end
66. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:dir) { ‘something’ }
context ‘when the method call is successful’ do
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
end
Expect the return from calling
the method on the instance
of the class
67. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:dir) { ‘something’ }
context ‘when the method call is successful’ do
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
end
To return true
68. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:dir) { ‘something’ }
context ‘when the method call is successful’ do
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
end
Spec Fails!
69. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
'sed: directory/*/.rb: No such file or directory'
let(:dir) { ‘something’ }
context ‘when the method call is successful’ do
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
end
70. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘when the method call is successful’ do
let(:directory_name) { ‘some_directory’ }
let(:sub_directory) { ‘some_sub_directory’ }
let(:file) { ‘some_file.rb’ }
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
end
Set the directory, subdirectory, and file names
71. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘when the method call is successful’ do
let(:directory_name) { ‘some_directory’ }
let(:sub_directory) { ‘some_sub_directory’ }
let(:file) { ‘some_file.rb’ }
before do
FileUtils.mkdir_p(File.join(directory_name, sub_directory))
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
end
Create directories and sub-directories
72. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘when the method call is successful’ do
let(:directory_name) { ‘some_directory’ }
let(:sub_directory) { ‘some_sub_directory’ }
let(:file) { ‘some_file.rb’ }
before do
FileUtils.mkdir_p(File.join(directory_name, sub_directory))
path = File
.join(directory_name,subdirectory_name,file_name)
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
end
Create the path for
the file
73. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘when the method call is successful’ do
let(:directory_name) { ‘some_directory’ }
let(:sub_directory) { ‘some_sub_directory’ }
let(:file) { ‘some_file.rb’ }
before do
FileUtils.mkdir_p(File.join(directory_name, sub_directory))
path = File
.join(directory_name,subdirectory_name,file_name)
file = File.new(path, ‘w’)
file.write(‘look, there is something in this file’)
file.close
end
it ‘returns true’ do
Create the actual file
74. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘when the method call is successful’ do
let(:directory_name) { ‘some_directory’ }
let(:sub_directory) { ‘some_sub_directory’ }
let(:file) { ‘some_file.rb’ }
before do
FileUtils.mkdir_p(File.join(directory_name, sub_directory))
path = File
.join(directory_name,subdirectory_name,file_name)
file = File.new(path, ‘w’)
file.write(‘look, there is something in this file’)
file.close
end
it ‘returns true’ do
Spec Passes!
75. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘when the method call is successful’ do
let(:directory_name) { ‘some_directory’ }
let(:sub_directory) { ‘some_sub_directory’ }
let(:file) { ‘some_file.rb’ }
before do
FileUtils.mkdir_p(File.join(directory_name, sub_directory))
path = File
.join(directory_name,subdirectory_name,file_name)
file = File.new(path, ‘w’)
file.write(‘look, there is something in this file’)
file.close
end
it ‘returns true’ do That’s a lot of setup code…
76. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
def create_required_directories_and_files(path, filename)
FileUtils.mkdir_p(File.join(path))
file = File.new(File.join(path,file_name), ‘w’)
file.write(‘look, there is something in this file’)
file.close
end
Takes a path and
file name
77. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
def create_required_directories_and_files(path, filename)
FileUtils.mkdir_p(File.join(path))
file = File.new(File.join(path,file_name), ‘w’)
file.write(‘look, there is something in this file’)
file.close
end
Makes the directories
78. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
def create_required_directories_and_files(path, filename)
FileUtils.mkdir_p(File.join(path))
file = File.new(File.join(path,file_name), ‘w’)
file.write(‘look, there is something in this file’)
file.close
end
Makes the file
79. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
before do
create_required_directories_and_files(
File.join(directory_name,subdirectory_name), file_name
)
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
Call the setup
method
80. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
before do
create_required_directories_and_files(
File.join(directory_name,subdirectory_name), file_name
)
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
Create and pass
the path for the file
81. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
before do
create_required_directories_and_files(
File.join(directory_name,subdirectory_name), file_name
)
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
Pass the file name
82. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
before do
create_required_directories_and_files(
File.join(directory_name,subdirectory_name), file_name
)
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
Spec Passes!
83. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
before do
create_required_directories_and_files(
File.join(directory_name,subdirectory_name), file_name
)
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
after do
FileUtils.rm_rf(directory_name)
end
Remove created
directories and file
84. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
before do
create_required_directories_and_files(
File.join(directory_name,subdirectory_name), file_name
)
end
it ‘returns true’ do
expect(do_system_things.do_the_thing(dir)).to eq(true)
end
after do
FileUtils.rm_rf(directory_name)
end
Spec Passes!
85. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
*pause*
86. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
sed is a streaming text editor
87. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
88. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
Find match for this pattern
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
89. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
Replace it with this pattern
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
90. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
91. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
//.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
92. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
end
93. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘'}
end
94. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {''}
it 'matches a string' do
end
end
95. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {''}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
96. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
//.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Returns nil if no successful match
97. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {''}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
Means it found a successful match
98. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {''}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
first character is ‘:’
99. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
add ‘:’ to string
100. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
Spec Fails!
101. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
add ‘:’ to regex
102. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Spec Passes!
103. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
Next character is alnum
character class
104. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:a'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
Add letter to test string
105. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
Spec Fails!
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:a'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
106. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:[[:alnum:]]/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
add alnum to regex
107. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:[[:alnum:]]/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Spec Passes!
108. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:a'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end Means character must
appear one or more times
109. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
Add character to test string
110. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
Spec Passes!
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
111. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
But…we were expecting a failure…
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string))
.not_to be_nil
end
end
112. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:[[:alnum:]]/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end Will return successful match with
only one character
113. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
end
Examining content of string that was
captured by the regex
114. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
Spec Fails!
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
end
115. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:[[:alnum:]]+/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
add + quantifier
116. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:[[:alnum:]]+/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Spec Passes!
117. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
Capture group
118. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
it ‘captures a group’ do
end
119. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
it ‘captures a group’ do
expect(do_system_things.first_regex_match(string)[1])
.not_to be_nil
end Testing that match captures
a capture group ([1] references
first capture group)
120. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
Spec Fails!
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
it ‘captures a group’ do
expect(do_system_things.first_regex_match(string)[1])
.not_to be_nil
end
121. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:[[:alnum:]]+()/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Adding empty capture group
122. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:[[:alnum:]]+()/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Spec Passes!
123. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
it ‘captures a group’ do
expect(do_system_things.first_regex_match(string)[1])
.not_to be_nil
expect(do_system_things.first_regex_match(string)[1])
.to eq(‘ab’)
end
Testing content of capture group
124. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
Spec Fails!
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
let(:string) {‘:ab'}
it 'matches a string' do
expect(do_system_things.first_regex_match(string)
.to_s).to include(‘:ab’)
end
it ‘captures a group’ do
expect(do_system_things.first_regex_match(string)[1])
.not_to be_nil
expect(do_system_things.first_regex_match(string)[1])
.to eq(‘ab’)
end
125. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:([[:alnum:]]+)/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Placing capture group in
correct place
126. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:([[:alnum:]]+)/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
Spec Passes!
127. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:([[:alnum:]]+)[[:space]]=>/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end Fast Forward…
128. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def first_regex_match(string)
/:([[:alnum:]]+)[[:space]]=>/.match(string)
end
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end We know what this
regex does!
129. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
before do
file = File.open(File.join(directory_path,file_name))
file.write(':ab =>')
file.close
end
end
Write sample string to file
130. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘changes the file’ do
original_contents =
File.read(File.join(directory_path,file_name))
end
end
Capture original contents of file
131. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘changes the file’ do
original_contents =
File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
end
end
Call the method
132. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘changes the file’ do
original_contents =
File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
new_contents = File.read
(File.join(directory_path,file_name))
end
end
Capture new contents of file
133. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘changes the file’ do
original_contents =
File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
new_contents = File.read
(File.join(directory_path,file_name))
expect(original_contents).not_to eq(new_contents)
end
end
Make sure file changes
134. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘changes the file’ do
original_contents =
File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
new_contents = File.read
(File.join(directory_path,file_name))
expect(original_contents).not_to eq(new_contents)
end
end
Spec Passes!
135. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
*pause*
136. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
Replace match for the
first pattern with this
second pattern
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
137. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
1:
138. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
1:
Escape - so we can use a literal
as the next character
139. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
1:
Uses the result of the first capture group
from the first pattern
140. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
1:
Adds a literal colon
141. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
‘:ab =>’
142. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
‘ab:’‘:ab =>’ replace with
143. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
let(:orig_string) { “:ab => “}
let(:new_string) { “ab: ‘}
it ‘changes the file’ do
original_contents = File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
new_contents = File.read(File.join(directory_path,file_name))
end
end
Expected content of file
before and after
144. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
let(:orig_string) { “:ab => “}
let(:new_string) { “ab: ‘}
it ‘changes the file’ do
original_contents = File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
new_contents = File.read(File.join(directory_path,file_name))
expect(new_contents).not_to include(orig_string)
expect(new_contents).to include(new_string)
end
end
Verify contents of
modified file
145. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
let(:orig_string) { “:ab => “}
let(:new_string) { “ab: ‘}
it ‘changes the file’ do
original_contents = File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
new_contents = File.read(File.join(directory_path,file_name))
expect(new_contents).not_to include(orig_string)
expect(new_contents).to include(new_string)
end
end
Spec Passes!
146. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
*pause*
147. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
Replace all matches for the
first pattern with the second
pattern
148. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
let(:orig_string) { “:ab => :ab =>“}
let(:new_string) { “ab: ab:’}
it ‘changes all matches within the file’ do
original_contents = File.read(File.join(directory_path,file_name))
do_system_things.do_the_thing(directory_name)
new_contents = File.read(File.join(directory_path,file_name))
expect(new_contents).not_to include(orig_string)
expect(new_contents).to include(new_string)
end
end
Expected content of
file before and after
149. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
let(:orig_string) { “:ab => :ab =>“}
let(:new_string) { “ab: ab:’}
it ‘changes all matches within the file’ do
original_contents = File.read(File.join(directory_path,file_name))
do_system_things(directory_name)
new_contents = File.read(File.join(directory_path,file_name))
expect(new_contents).not_to include(orig_string)
expect(new_contents).to include(new_string)
end
end Spec Passes!
150. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/"
#{dir}/**/*.rb"
end
end
Taking out the
global flag
151. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/"
#{dir}/**/*.rb"
end
end
Spec Fails!
152. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Putting the flag
back in
153. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Passes!
154. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Take -E flag out
155. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Fails!
156. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Put -E flag back in
157. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Passes!
158. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
-i flag: sed alters
files in place
159. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
-i flag: sed alters
files in place
Passing an empty
extension
160. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘does not save a backup copy of the file’ do
expect
(Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
end
end
Expect only one file in
directory/subdirectory
path
161. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘does not save a backup copy of the file’ do
expect
(Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
do_system_things.do_the_thing(directory_name)
end
end
Call the method
162. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘does not save a backup copy of the file’ do
expect
(Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
do_system_things.do_the_thing(directory_name)
expect(
Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
end
end
Expect only one file in
directory/subdirectory
path
163. First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
context ‘changing the file’ do
it ‘does not save a backup copy of the file’ do
expect
(Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
do_system_things.do_the_thing(directory_name)
expect
(Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
end
end
Spec Passes!
164. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Pass extension to -i flag
165. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Fails!
166. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Passing an empty
extension again
167. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Passes!
168. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
We know what this does!
170. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
171. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
end
172. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
#{dir}/**/*.rb"
end
private
def substitute_command
's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
end
end
173. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' #{substitute_command} #{dir}/**/*.rb"
end
private
def substitute_command
's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
end
end
174. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' #{substitute_command} #{dir}/**/*.rb"
end
private
def substitute_command
's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
end
end
Spec Passes!
175. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' #{substitute_command} #{dir}/**/*.rb"
end
private
def substitute_command
's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
end
end Really old regex syntax
176. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' #{substitute_command} #{dir}/**/*.rb"
end
private
def substitute_command
’s/:(w+)s=>/1:/g’
end
end New regex syntax
177. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' #{substitute_command} #{dir}/**/*.rb"
end
private
def substitute_command
’s/:(w+)s=>/1:/g’
end
end Spec Fails!
178. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' #{substitute_command} #{dir}/**/*.rb"
end
private
def substitute_command
's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
end
end Back to the old
regex syntax
179. First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
system "sed -E -i '' #{substitute_command} #{dir}/**/*.rb"
end
private
def substitute_command
's/:([[:alnum:]]+)[[:space:]]=>/1:/g'
end
end
Spec Passes!
181. What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to know two things decisively
182. What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to know two things decisively
1) Does the behavior still exist?
183. What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to know two things decisively
1) Does the behavior still exist?
2) Is it connected correctly?
184. What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
What about QA?
185. What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Ideally, QA should find nothing
186. What if something goes wrong?
First Do No Harm: Surgical Refactoring @nellshamrell
187. What if something goes wrong?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Take responsibility - what your code does
in production is your responsibility
188. What if something goes wrong?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Take responsibility - what your code does
in production is your responsibility
2) Evaluate risk of another change
(a change to a change is still a change)
189. What if something goes wrong?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Take responsibility - what your code does
in production is your responsibility
2) Evaluate risk of another change
(a change to a change is still a change)
3) Fix the problem (if you can’t, find someone
who can!)
190. Thank You!
First Do No Harm: Surgical Refactoring @nellshamrell
Nell Shamrell-Harrington
Software Development Engineer at Chef
@nellshamrell
www.nellshamrell.com
nshamrell@chef.io
191. Thank You!
First Do No Harm: Surgical Refactoring @nellshamrell
Nell Shamrell-Harrington
Software Development Engineer at Chef
@nellshamrell
www.nellshamrell.com
nshamrell@chef.io
Thank you
Jim and Jen!!!!