[소프트웨어 공학]리팩터링 1장

bluejoy·2022년 1월 29일
1

소프트웨어 공학

목록 보기
1/4

읽게된 계기

코드를 어떻게 짜야할지 가이드 라인을 잡고 싶어서 구매했다. 클린코드도 이미 읽어봤지만 언어가 자바인 것도 있고, 한권 더 읽어보고 싶어서 구매했다.
사실 내 돈이 아니여서 막 질렀다 ㅋㅋ.
당분간 이 책을 보면서 내용을 정리하며 익히려 한다.
리팩터링 2판

1.1 시작

1장에서 리팩터링이 뭔지 보여주기 위한 간단한 예시 프로그램을 들어준다. 연극 종류와 연극 공연 요청 정보가 있을 때 청구 내역을 출력하는 프로그램이다.

1.2 소감

  • 프로그램이 새로운 기능을 추가하기에 편한 구조가 아니라면, 먼저 기능을 추가하기 쉬운 형태로 리팩터링하고 나서 원하는 기능을 추가한다.

2가지 변경사항이 주어지는데
1. 청구 내역을 HTML로 출력해야한다.
2. 현재 장르는 비극과 희극 두가지 뿐이지만 다양한 장르에 대해서도 청구 내역을 계산하고 싶다.

현재 로직이 완벽하고 변경할 일이 절대 없다면 상관 없지만 변경할 일이 있다면 리팩터링이 필요하다. 리팩터링을 이용해 다양한 변경에도 쉽게 대응가능하게 만들어줘야한다.

코멘트

객체 지향 5원칙(SOLID)의 개방-폐쇄 원칙이 생각난다.

1.3 리팩터링의 첫 단계

리팩터링의 첫 단계는 항상 테스트 코드 작성부터이다.

  • 리팩터링하기 전에 제대로 된 테스트부터 마련한다. 테스트는 반드시 자가진단하도록 만든다.
    여기서는 테스트 작성은 나중 챕터에서 설명하고 넘어갔다.

코멘트

TDD 매우매우 중요하지~

1.4 statement() 함수 쪼개기

함수 추출하기

switch문을 분리해서 함수로 만들기로 했다. 한번의 공연에 대한 요금을 계산하고 있으므로 이름을 amountFor(aPerformance)으로 지어 추출해준다.
이 추출 절차를 함수 추출하기라고 한다.
1. 유효 범위를 벗어나는 변수, 즉 새 함수에서는 곧바로 사용할 수 없는 변수가 있는지 확인한다.
2. 함수 안에서 값이 변하는 변수는 유의해서 처리한다. 하나일 경우 해당 변수를 반환하도록 작성한다.

주의할점은 매번 변경할때마다 테스트를 해줘야한다는 것이다. 조심씩 수정하고 피드백 주기를 짧게 가져가야한다. (커밋도 테스트 후 매번 수행!)

  • 리팩터링은 프로그램 수정을 작은 단계로 나눠 진행한다. 그래서 중간에 실수하더라도 버그를 쉽게 찾을 수 있다.

IDE에서 자동으로 진행해 주기도 함.

매개 변수들 확인?

함수를 추출했다면 함수 코드를 자세히 들여다보면서 명확하게 바꿀 방법을 찾는다.
ex) 함수의 반환 값을 나타내는 변수를 result로, 함수의 매개 변수를 좀 더 명확하게.

간단한 예시 대충 비슷하게 맞춤.
매번 질의를 해주는 임시 변수들 찾는다. 아래에서는 play[perf.id]가 된다.

// aPerformance = 변수명 명확하게
function amountFor(aPerformance, play){
  result += play;
  // do something
}

for(perf of perfs){
  const play = play[perf.id];
  console.log(amountFor(perf,play));
  // do something with play
}

임시 변수를 질의 함수로 바꾸기변수 인라인하기 적용.

function playFor(aPerformance){
  return play[aPerformance.id]
}
function amountFor(aPerformance, play){
  result += play;
  // do something
}
// 인라인 변수로
for(perf of perfs){
  console.log(amountFor(perf, playFor(aPerformance)))
  // do something with playFor(aPerformance)
}

함수 선언 바꾸기를 적용 -> 아직 잘 모름.

// play가 인자로 올 필요가 없으므로 분리
function playFor(aPerformance){
  return play[aPerformance.id]
}
function amountFor(aPerformance){
  result += playFor[aPerformance.id];
  // do something
}

for(perf of perfs){
  console.log(amountFor(perf, playFor(aPerformance)))
  // do something with playFor(aPerformance)
}

매 과정이 진행될때마다 컴파일-테스트-커밋을 수행해야한다.

반복

이런식으로 계속 함수를 쪼개고 명로하게 만든다. 결국 메인 함수는 매우 적어지고 계산 로직들은 여러 개의 보조 함수로 빼내진다.

코멘트

값이 변하는 변수가 여러개일때는 object를 반환해야하나?
이렇게 인자를 줄이는건 테스트를 단순화하기 위해서?
저렇게 인라인 함수로 여러번 호출하는건 왜 좋은지 모르겠다.
나중에 각각의 해당 챕터를 읽어봐야할 듯.

1.6 계산 단계와 포맷팅 단계 분리하기

청구서를 계산하는 단계를 분리해 별도의 모듈로 만든다.포맷팅 단계에서 html 출력을 담당하게 만든다.

1.8 다형성을 활용해 계산 코드 재구성하기

조건부 로직을 다형성으로 바꾸기를 사용한다. 현재 연극의 종류에 따라 다르게 청구서를 계산하는 부분을 case문으로 처리하고 있는데 이를 공연료 계산기 슈퍼클래스(부모 클래스)를 만든다. 조건부 로직을 다형성으로 하기 위해 포인트 계산 방식이 다른 처리 로직을 서브 클래스(자식 클래스)로 만든다.

1.10 마치며

이 챕터는 리팩터링에 대한 감을 잡는 챕터이다.

  • 좋은 코드를 가늠하는 확실한 방법은 '얼마나 수정하기 쉬운가'다.

후기

코드가 보기 좋다고 좋은 코드가 아니다.
나중에 뒷장들을 읽고 여기 예시를 좀 제대로 채워 넣어야할듯.
아직은 무슨 기법이 들어가는지 잘 모르겠어서 예시를 채우기가 힘들다.

그래도 핵심은

  • 로직을 쪼개고 분리해 명로하게 만든다.
  • 수정에 열려 있게 만든다.
  • 매 과정이 진행될때마다 컴파일-테스트-커밋을 수행해야다.

이 정도인것 같다. 너무 어렵네

profile
개발자 지망생입니다.

4개의 댓글

comment-user-thumbnail
2022년 1월 30일

본문에 나온 질문에 대한 제 생각을 정리해봤어요.

값이 변하는 변수가 여러개일때는 object를 반환해야하나?
=> 타입을 사용하면 object를 반환하더라도 활용하기 좋습니다. 특히 ts를 사용하면 js의 destructuring을 사용할 수 있어 object로 된 반환도 다양하게 재사용할 수 있습니다. ts를 사용하기 어렵다면 jsdoc을 사용하면 ide의 도움을 받을 수도 있습니다.

이렇게 인자를 줄이는건 테스트를 단순화하기 위해서?
=> 인자가 많아지면 순서 외우기 등 사용하기 까다롭죠. 인자가 많다는건 그만큼 여러 의존성이 섞여있다는거니 재사용성도 떨어질 듯..?

저렇게 인라인 함수로 여러번 호출하는건 왜 좋은지 모르겠다.
=> 코드 한줄 한줄이 가지는 의미가 명확해진다고 생각해요. 주석 없이 코드만 보고 의미를 알 수 있도록

3개의 답글