first do no harm: surgical refactoring

191
First Do No Harm Surgical Refactoring Nell Shamrell-Harrington @nellshamrell

Upload: nell-shamrell-harrington

Post on 11-Jan-2017

1.311 views

Category:

Technology


0 download

TRANSCRIPT

First Do No HarmSurgical 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…

TransportationEnergy sources

But…it’s not life or death, right?

First Do No Harm: Surgical Refactoring @nellshamrell

Software is being integrated into…

TransportationEnergy sourcesMedical 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 Approaches1) Edit and Pray

How should I refactor?

First Do No Harm: Surgical Refactoring @nellshamrell

2 Common Approaches1) Edit and Pray

2) Cover and Modify

How should I refactor?

First Do No Harm: Surgical Refactoring @nellshamrell

2 Common Approaches1) 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 changeAnd 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 refactoring2) 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 somethingCode is too inefficient

What is a necessary refactoring?

First Do No Harm: Surgical Refactoring @nellshamrell

Need to add somethingCode 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 usNo 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

endExecutes 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

endIn 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

endWhat 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 call 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 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

endAdding 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

endPlacing 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…

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!

First Do No Harm: Surgical Refactoring @nellshamrell

spec/do_system_things_spec.rbcontext ‘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

First Do No Harm: Surgical Refactoring @nellshamrell

spec/do_system_things_spec.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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.rbcontext ‘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 -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/\\1:/g" #{dir}/**/*.rb" end

end

Take -E flag out

First Do No Harm: Surgical Refactoring @nellshamrell

lib/do_system_things.rb

class DoSystemThings

def do_the_thing(dir) system "sed -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/\\1:/g" #{dir}/**/*.rb" end

end

Spec Fails!

First Do No Harm: Surgical Refactoring @nellshamrell

lib/do_system_things.rb

class DoSystemThings

def do_the_thing(dir) system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/\\1:/g" #{dir}/**/*.rb" end

end

Put -E flag back in

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

-i flag: sed alters files in place

First Do No Harm: Surgical Refactoring @nellshamrell

lib/do_system_things.rb

class DoSystemThings

def do_the_thing(dir) system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/\\1:/g" #{dir}/**/*.rb" end

end

-i flag: sed alters files in place

Passing an empty extension

First Do No Harm: Surgical Refactoring @nellshamrell

spec/do_system_things_spec.rbcontext ‘changing the file’ do

it ‘does not save a backup copy of the file’ do expect (Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1)

end end

Expect only one file in directory/subdirectory path

First Do No Harm: Surgical Refactoring @nellshamrell

spec/do_system_things_spec.rbcontext ‘changing the file’ do

it ‘does not save a backup copy of the file’ do expect (Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1)

do_system_things.do_the_thing(directory_name)

end end

Call the method

First Do No Harm: Surgical Refactoring @nellshamrell

spec/do_system_things_spec.rbcontext ‘changing the file’ do

it ‘does not save a backup copy of the file’ do expect (Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1)

do_system_things.do_the_thing(directory_name)

expect( Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1) end end

Expect only one file in directory/subdirectory path

First Do No Harm: Surgical Refactoring @nellshamrell

spec/do_system_things_spec.rbcontext ‘changing the file’ do

it ‘does not save a backup copy of the file’ do expect (Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1)

do_system_things.do_the_thing(directory_name)

expect (Dir[“#{directory_name}/#{subdirectory_name}/*”] .count).to eq(1) end end

Spec Passes!

First Do No Harm: Surgical Refactoring @nellshamrell

lib/do_system_things.rb

class DoSystemThings

def do_the_thing(dir) system "sed -E -i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/\\1:/g" #{dir}/**/*.rb" end

end

Pass extension to -i flag

First Do No Harm: Surgical Refactoring @nellshamrell

lib/do_system_things.rb

class DoSystemThings

def do_the_thing(dir) system "sed -E -i .tmp ’s/:([[:alnum:]]+)[[:space:]]=>/\\1:/g" #{dir}/**/*.rb" end

end

Spec Fails!

First Do No Harm: Surgical Refactoring @nellshamrell

lib/do_system_things.rb

class DoSystemThings

def do_the_thing(dir) system "sed -E -i '' ’s/:([[:alnum:]]+)[[:space:]]=>/\\1:/g" #{dir}/**/*.rb" end

end

Passing an empty extension again

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

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

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 '' #{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 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 '' #{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

Spec Passes!

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!)

Thank You!

First Do No Harm: Surgical Refactoring @nellshamrell

Nell Shamrell-Harrington

Software Development Engineer at Chef

@nellshamrell

www.nellshamrell.com

[email protected]

Thank You!

First Do No Harm: Surgical Refactoring @nellshamrell

Nell Shamrell-Harrington

Software Development Engineer at Chef

@nellshamrell

www.nellshamrell.com

[email protected]

Thank you Jim and Jen!!!!