SlideShare a Scribd company logo
1 of 192
Download to read offline
First Do No Harm
Surgical Refactoring
Nell Shamrell-Harrington
@nellshamrell
Section I:
Refactoring
First Do No Harm: Surgical Refactoring @nellshamrell
First Do No Harm: Surgical Refactoring @nellshamrell
Refactoring is a change
and changes can go wrong
What is refactoring?
But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
Software is being integrated into…
But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
Software is being integrated into…
Transportation
But…it’s not life or death, right?
First Do No Harm: Surgical Refactoring @nellshamrell
Software is being integrated into…
Transportation
Energy sources
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
So…is refactoring bad, then?
First Do No Harm: Surgical Refactoring @nellshamrell
So…is refactoring bad, then?
First Do No Harm: Surgical Refactoring @nellshamrell
Refactoring is neither inherently good OR bad
So…is refactoring bad, then?
First Do No Harm: Surgical Refactoring @nellshamrell
How you do it is what matters
How should I refactor?
First Do No Harm: Surgical Refactoring @nellshamrell
2 Common Approaches
How should I refactor?
First Do No Harm: Surgical Refactoring @nellshamrell
2 Common Approaches
1) Edit and Pray
How should I refactor?
First Do No Harm: Surgical Refactoring @nellshamrell
2 Common Approaches
1) Edit and Pray
2) Cover and Modify
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”
Section II:
Surgical Refactoring
First Do No Harm: Surgical Refactoring @nellshamrell
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
What is surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
First do no harm!
First Do No Harm: Surgical Refactoring @nellshamrell
Surgical refactoring is a series of
good habits that reduce risk
What is surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
2 categories of refactoring
What is surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
2 categories of refactoring
What is surgical refactoring?
1) Necessary refactoring
First Do No Harm: Surgical Refactoring @nellshamrell
2 categories of refactoring
What is surgical refactoring?
1) Necessary refactoring
2) Cosmetic refactoring
What is a necessary refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to add something
What is a necessary refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to add something
Code is too inefficient
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
What is a necessary refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Necessary refactorings have a
moderate to high risk tolerance
What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
No business need to change code
What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Something about it just bugs us
No business need to change code
What is a cosmetic refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Cosmetic refactorings
have a low risk tolerance
What about whitespace refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
What about whitespace refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Ultimate cosmetic refactoring
What about whitespace refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Ultimate cosmetic refactoring
Get a style guide
(i.e. Github style guide)
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!
What’s involved in surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
What’s involved in surgical refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Pre-op: what to do before touching the code
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
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
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!
Section IV:
Pre-Op
First Do No Harm: Surgical Refactoring @nellshamrell
What is involved in pre-op?
First Do No Harm: Surgical Refactoring @nellshamrell
Diagnosis
(What exactly does the code do?)
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
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
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
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
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
So…do we know what it does?
First Do No Harm: Surgical Refactoring @nellshamrell
So…do we know what it does?
First Do No Harm: Surgical Refactoring @nellshamrell
Map is influenced by our own
experiences and expectations
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
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
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?
First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
let(:do_system_things) { DoSystemThings.new }
Instantiate the class
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
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
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
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
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
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!
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
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!
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
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!
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?
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 method returns true
when the command executes
successfully
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
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
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
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!
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
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
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
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
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
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!
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…
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
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
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
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
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
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
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!
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
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!
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*
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
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
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
Find match for this pattern
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
Replace it with this pattern
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
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
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
First Do No Harm: Surgical Refactoring @nellshamrell
spec/do_system_things_spec.rb
describe ‘what the regex matches’
# FOR REFERENCE: /:([[:alnum:]]+)[[:space:]]=>/
end
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
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
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 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
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
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 ‘:’
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
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!
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
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!
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
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
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
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
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!
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
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
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
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
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 alnum character
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
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
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
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!
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
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
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)
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
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
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!
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
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
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
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!
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…
(Adding in tests for rest of characters)
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!
‘:ab =>’ matches!
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
(note the space and hash rocket)
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
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
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
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
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!
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*
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'
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
1:
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
1:
Escape - so we can use a literal 
as the next character
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
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
1:
Adds a literal colon
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
‘:ab =>’
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
s/:([[:alnum:]]+)[[:space:]]=>/1:/g'
‘ab:’‘:ab =>’ replace with
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
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
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!
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*
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
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
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!
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
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!
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
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!
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
Next step…add in tests for these flags
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# taking the -E flag out
system "sed -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# taking the -E flag out
system "sed -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Fails!
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# putting the -E flag back in
system "sed E —i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# putting the -E flag back in
system "sed E —i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# putting the -E flag back in
system "sed E —i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Passes!
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
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 the subdirectory we created to contain only one file
expect(Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
end
end
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 the subdirectory we created to contain only one file
expect(Dir[“#{directory_name}/#{subdirectory_name}/*”]
.count).to eq(1)
do_system_things.do_the_thing(directory_name)
end
end
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 the subdirectory we created to contain only one file
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
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 the subdirectory we created to contain only one file
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!
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# adding an extension to the -i flag
system "sed E —i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# adding an extension to the -i flag
system "sed E —i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb”
end
end
Spec Fails!
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# removing extension to -i flag
system "sed E —i ‘’ ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
First Do No Harm: Surgical Refactoring @nellshamrell
lib/do_system_things.rb
class DoSystemThings
def do_the_thing(dir)
# removing extension to -i flag
system "sed E —i ‘’ ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g"
#{dir}/**/*.rb"
end
end
Spec Passes!
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!
Section V:
Operation
First Do No Harm: Surgical Refactoring @nellshamrell
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
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
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
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
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
Specs Pass!
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
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
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 Specs Fail!
w != [:alnum]
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
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
Specs Pass!
Section VI:
Recovery
First Do No Harm: Surgical Refactoring @nellshamrell
What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Need to know two things decisively
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?
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?
What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
What about QA?
What do I need to do after refactoring?
First Do No Harm: Surgical Refactoring @nellshamrell
Ideally, QA should find nothing
What if something goes wrong?
First Do No Harm: Surgical Refactoring @nellshamrell
What if something goes wrong?
First Do No Harm: Surgical Refactoring @nellshamrell
1) Take responsibility - what your code does
in production is your responsibility
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)
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!)
Conclusion
First Do No Harm: Surgical Refactoring @nellshamrell
“I’m not a great programmer, I’m just a good
programmer with great habits”
- “Refactoring: Ruby Edition”
Thank You!
First Do No Harm: Surgical Refactoring @nellshamrell
Nell Shamrell-Harrington
Software Development Engineer at Chef
@nellshamrell
www.nellshamrell.com
nshamrell@chef.io

More Related Content

Viewers also liked

Mika Raunio - Open Innovation Platforms - Mindtrek 2016
Mika Raunio - Open Innovation Platforms - Mindtrek 2016Mika Raunio - Open Innovation Platforms - Mindtrek 2016
Mika Raunio - Open Innovation Platforms - Mindtrek 2016Mindtrek
 
Beginners Guide to Modeling with Maya
Beginners Guide to Modeling with MayaBeginners Guide to Modeling with Maya
Beginners Guide to Modeling with MayaPaddy Lock
 
AWS Startup Tech Lightning Talks 2015 Summer at dots.
AWS Startup Tech Lightning Talks 2015 Summer at dots.AWS Startup Tech Lightning Talks 2015 Summer at dots.
AWS Startup Tech Lightning Talks 2015 Summer at dots.Eiji Shinohara
 
Monitoring patterns for mitigating technical risk
Monitoring patterns for  mitigating technical riskMonitoring patterns for  mitigating technical risk
Monitoring patterns for mitigating technical riskItai Frenkel
 
Neptune : Re-thinking Incident Response Automation
Neptune : Re-thinking Incident Response Automation Neptune : Re-thinking Incident Response Automation
Neptune : Re-thinking Incident Response Automation Kiran Gollu
 
Scalone dokumenty (27)
Scalone dokumenty (27)Scalone dokumenty (27)
Scalone dokumenty (27)gemix gemix
 

Viewers also liked (8)

NPSO
NPSONPSO
NPSO
 
Mika Raunio - Open Innovation Platforms - Mindtrek 2016
Mika Raunio - Open Innovation Platforms - Mindtrek 2016Mika Raunio - Open Innovation Platforms - Mindtrek 2016
Mika Raunio - Open Innovation Platforms - Mindtrek 2016
 
Beginners Guide to Modeling with Maya
Beginners Guide to Modeling with MayaBeginners Guide to Modeling with Maya
Beginners Guide to Modeling with Maya
 
DevOps Case Studies
DevOps Case StudiesDevOps Case Studies
DevOps Case Studies
 
AWS Startup Tech Lightning Talks 2015 Summer at dots.
AWS Startup Tech Lightning Talks 2015 Summer at dots.AWS Startup Tech Lightning Talks 2015 Summer at dots.
AWS Startup Tech Lightning Talks 2015 Summer at dots.
 
Monitoring patterns for mitigating technical risk
Monitoring patterns for  mitigating technical riskMonitoring patterns for  mitigating technical risk
Monitoring patterns for mitigating technical risk
 
Neptune : Re-thinking Incident Response Automation
Neptune : Re-thinking Incident Response Automation Neptune : Re-thinking Incident Response Automation
Neptune : Re-thinking Incident Response Automation
 
Scalone dokumenty (27)
Scalone dokumenty (27)Scalone dokumenty (27)
Scalone dokumenty (27)
 

Similar to First Do No Harm: Surgical Refactoring (extended edition)

The limits of unit testing by Craig Stuntz
The limits of unit testing by Craig StuntzThe limits of unit testing by Craig Stuntz
The limits of unit testing by Craig StuntzQA or the Highway
 
The Limits of Unit Testing by Craig Stuntz
The Limits of Unit Testing by Craig StuntzThe Limits of Unit Testing by Craig Stuntz
The Limits of Unit Testing by Craig StuntzQA or the Highway
 
Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!Matt Eland
 
Simple Essay Example Amat
Simple Essay Example  AmatSimple Essay Example  Amat
Simple Essay Example AmatJennifer Moore
 
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...PVS-Studio
 
SRE Lessons for the Enterprise
SRE Lessons for the Enterprise SRE Lessons for the Enterprise
SRE Lessons for the Enterprise Rundeck
 
Normal accidents and outpatient surgeries
Normal accidents and outpatient surgeriesNormal accidents and outpatient surgeries
Normal accidents and outpatient surgeriesJonathan Creasy
 

Similar to First Do No Harm: Surgical Refactoring (extended edition) (11)

The limits of unit testing by Craig Stuntz
The limits of unit testing by Craig StuntzThe limits of unit testing by Craig Stuntz
The limits of unit testing by Craig Stuntz
 
The Limits of Unit Testing by Craig Stuntz
The Limits of Unit Testing by Craig StuntzThe Limits of Unit Testing by Craig Stuntz
The Limits of Unit Testing by Craig Stuntz
 
Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!Stand back; I'm going to try Scientist!
Stand back; I'm going to try Scientist!
 
Model-checking for efficient malware detection
Model-checking for efficient malware detectionModel-checking for efficient malware detection
Model-checking for efficient malware detection
 
Simple Essay Example Amat
Simple Essay Example  AmatSimple Essay Example  Amat
Simple Essay Example Amat
 
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
Characteristics of PVS-Studio Analyzer by the Example of EFL Core Libraries, ...
 
Art_of_DefectReporting080214
Art_of_DefectReporting080214Art_of_DefectReporting080214
Art_of_DefectReporting080214
 
Quality tools
Quality toolsQuality tools
Quality tools
 
Rtt preso
Rtt presoRtt preso
Rtt preso
 
SRE Lessons for the Enterprise
SRE Lessons for the Enterprise SRE Lessons for the Enterprise
SRE Lessons for the Enterprise
 
Normal accidents and outpatient surgeries
Normal accidents and outpatient surgeriesNormal accidents and outpatient surgeries
Normal accidents and outpatient surgeries
 

More from Nell Shamrell-Harrington

This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!Nell Shamrell-Harrington
 
Higher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with HabitatHigher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with HabitatNell Shamrell-Harrington
 
Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!Nell Shamrell-Harrington
 
Creating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef HabitatCreating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef HabitatNell Shamrell-Harrington
 
A Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef SupermarketA Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef SupermarketNell Shamrell-Harrington
 

More from Nell Shamrell-Harrington (20)

This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!This Week in Rust: 400 Issues and Counting!
This Week in Rust: 400 Issues and Counting!
 
The Rust Borrow Checker
The Rust Borrow CheckerThe Rust Borrow Checker
The Rust Borrow Checker
 
Higher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with HabitatHigher. Faster. Stronger. Your Applications with Habitat
Higher. Faster. Stronger. Your Applications with Habitat
 
Habitat Service Discovery
Habitat Service DiscoveryHabitat Service Discovery
Habitat Service Discovery
 
Web Operations101
Web Operations101Web Operations101
Web Operations101
 
Rust Traits And You: A Deep Dive
Rust Traits And You: A Deep DiveRust Traits And You: A Deep Dive
Rust Traits And You: A Deep Dive
 
Rust, Redis, and Protobuf - Oh My!
Rust, Redis, and Protobuf - Oh My!Rust, Redis, and Protobuf - Oh My!
Rust, Redis, and Protobuf - Oh My!
 
Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!Containers, Virtual Machines, and Bare Metal, Oh My!
Containers, Virtual Machines, and Bare Metal, Oh My!
 
Chef Vault: A Deep Dive
Chef Vault: A Deep DiveChef Vault: A Deep Dive
Chef Vault: A Deep Dive
 
Open Source Governance 101
Open Source Governance 101Open Source Governance 101
Open Source Governance 101
 
DevOps in Politics
DevOps in PoliticsDevOps in Politics
DevOps in Politics
 
Open Source Governance - The Hard Parts
Open Source Governance - The Hard PartsOpen Source Governance - The Hard Parts
Open Source Governance - The Hard Parts
 
Creating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef HabitatCreating Packages that Run Anywhere with Chef Habitat
Creating Packages that Run Anywhere with Chef Habitat
 
Refactoring terraform
Refactoring terraformRefactoring terraform
Refactoring terraform
 
Refactoring Infrastructure Code
Refactoring Infrastructure CodeRefactoring Infrastructure Code
Refactoring Infrastructure Code
 
Devops: A History
Devops: A HistoryDevops: A History
Devops: A History
 
First Do No Harm: Surgical Refactoring
First Do No Harm: Surgical RefactoringFirst Do No Harm: Surgical Refactoring
First Do No Harm: Surgical Refactoring
 
A Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef SupermarketA Supermarket of Your Own: Running a Private Chef Supermarket
A Supermarket of Your Own: Running a Private Chef Supermarket
 
Public Supermarket: The Insider's Tour
Public Supermarket: The Insider's TourPublic Supermarket: The Insider's Tour
Public Supermarket: The Insider's Tour
 
Beneath the Surface - Rubyconf 2013
Beneath the Surface - Rubyconf 2013Beneath the Surface - Rubyconf 2013
Beneath the Surface - Rubyconf 2013
 

Recently uploaded

WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisamasabamasaba
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...Shane Coughlan
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburgmasabamasaba
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyviewmasabamasaba
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxAnnaArtyushina1
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfonteinmasabamasaba
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplatePresentation.STUDIO
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationJuha-Pekka Tolvanen
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...masabamasaba
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park masabamasaba
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2
 

Recently uploaded (20)

WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With SimplicityWSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
WSO2Con2024 - Enabling Transactional System's Exponential Growth With Simplicity
 
WSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - KeynoteWSO2Con204 - Hard Rock Presentation - Keynote
WSO2Con204 - Hard Rock Presentation - Keynote
 
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa%in tembisa+277-882-255-28 abortion pills for sale in tembisa
%in tembisa+277-882-255-28 abortion pills for sale in tembisa
 
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
Abortion Pill Prices Tembisa [(+27832195400*)] 🏥 Women's Abortion Clinic in T...
 
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
OpenChain - The Ramifications of ISO/IEC 5230 and ISO/IEC 18974 for Legal Pro...
 
WSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security ProgramWSO2CON 2024 - How to Run a Security Program
WSO2CON 2024 - How to Run a Security Program
 
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
WSO2CON 2024 - Cloud Native Middleware: Domain-Driven Design, Cell-Based Arch...
 
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
%in Rustenburg+277-882-255-28 abortion pills for sale in Rustenburg
 
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
%in Hazyview+277-882-255-28 abortion pills for sale in Hazyview
 
Artyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptxArtyushina_Guest lecture_YorkU CS May 2024.pptx
Artyushina_Guest lecture_YorkU CS May 2024.pptx
 
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
WSO2CON 2024 - Building the API First Enterprise – Running an API Program, fr...
 
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
%in Stilfontein+277-882-255-28 abortion pills for sale in Stilfontein
 
AI & Machine Learning Presentation Template
AI & Machine Learning Presentation TemplateAI & Machine Learning Presentation Template
AI & Machine Learning Presentation Template
 
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
WSO2CON 2024 - Navigating API Complexity: REST, GraphQL, gRPC, Websocket, Web...
 
What Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the SituationWhat Goes Wrong with Language Definitions and How to Improve the Situation
What Goes Wrong with Language Definitions and How to Improve the Situation
 
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
%+27788225528 love spells in Atlanta Psychic Readings, Attraction spells,Brin...
 
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
WSO2CON 2024 - API Management Usage at La Poste and Its Impact on Business an...
 
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park %in ivory park+277-882-255-28 abortion pills for sale in ivory park
%in ivory park+277-882-255-28 abortion pills for sale in ivory park
 
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
Abortion Pills In Pretoria ](+27832195400*)[ 🏥 Women's Abortion Clinic In Pre...
 
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital TransformationWSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
WSO2Con2024 - WSO2's IAM Vision: Identity-Led Digital Transformation
 

First Do No Harm: Surgical Refactoring (extended edition)

  • 1. First Do No Harm Surgical Refactoring Nell Shamrell-Harrington @nellshamrell
  • 2. Section I: Refactoring First Do No Harm: Surgical Refactoring @nellshamrell
  • 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
  • 9. So…is refactoring bad, then? First Do No Harm: Surgical Refactoring @nellshamrell
  • 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”
  • 16. Section II: Surgical Refactoring First Do No Harm: Surgical Refactoring @nellshamrell
  • 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!
  • 40. Section IV: Pre-Op First Do No Harm: Surgical Refactoring @nellshamrell
  • 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 method 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 alnum 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… (Adding in tests for rest of characters)
  • 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! ‘:ab =>’ matches!
  • 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 (note the space and hash rocket)
  • 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 -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end Next step…add in tests for these flags
  • 155. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # taking the -E flag out system "sed -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end
  • 156. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # taking the -E flag out system "sed -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end Spec Fails!
  • 157. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # putting the -E flag back in system "sed E —i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end
  • 158. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # putting the -E flag back in system "sed E —i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end
  • 159. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # putting the -E flag back in system "sed E —i '' ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end Spec Passes!
  • 160. 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
  • 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 the subdirectory we created to contain only one file expect(Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1) end end
  • 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 the subdirectory we created to contain only one file expect(Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1) do_system_things.do_the_thing(directory_name) end end
  • 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 the subdirectory we created to contain only one file 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
  • 164. 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 the subdirectory we created to contain only one file 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!
  • 165. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # adding an extension to the -i flag system "sed E —i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end
  • 166. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # adding an extension to the -i flag system "sed E —i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb” end end Spec Fails!
  • 167. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # removing extension to -i flag system "sed E —i ‘’ ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end
  • 168. First Do No Harm: Surgical Refactoring @nellshamrell lib/do_system_things.rb class DoSystemThings def do_the_thing(dir) # removing extension to -i flag system "sed E —i ‘’ ’s/:([[:alnum:]]+)[[:space:]]=>/1:/g" #{dir}/**/*.rb" end end Spec Passes!
  • 169. 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. Section V: Operation First Do No Harm: Surgical Refactoring @nellshamrell
  • 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 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 '' 's/:([[:alnum:]]+)[[:space:]]=>/1:/g' #{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
  • 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 Specs Pass!
  • 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/:([[:alnum:]]+)[[:space:]]=>/1:/g' end end Really old 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 New regex syntax
  • 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/:(w+)s=>/1:/g’ end end Specs Fail! w != [:alnum]
  • 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 Back to the old regex syntax
  • 180. 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 Specs Pass!
  • 181. Section VI: Recovery First Do No Harm: Surgical Refactoring @nellshamrell
  • 182. What do I need to do after refactoring? First Do No Harm: Surgical Refactoring @nellshamrell Need to know two things decisively
  • 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?
  • 184. 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?
  • 185. What do I need to do after refactoring? First Do No Harm: Surgical Refactoring @nellshamrell What about QA?
  • 186. What do I need to do after refactoring? First Do No Harm: Surgical Refactoring @nellshamrell Ideally, QA should find nothing
  • 187. What if something goes wrong? First Do No Harm: Surgical Refactoring @nellshamrell
  • 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
  • 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)
  • 190. 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!)
  • 191. Conclusion First Do No Harm: Surgical Refactoring @nellshamrell “I’m not a great programmer, I’m just a good programmer with great habits” - “Refactoring: Ruby Edition”
  • 192. Thank You! First Do No Harm: Surgical Refactoring @nellshamrell Nell Shamrell-Harrington Software Development Engineer at Chef @nellshamrell www.nellshamrell.com nshamrell@chef.io