[Refactoring] 리팩터링 2판 Chapter.06 part 3 (기본적인 리팩터링)
카테고리: Refactoring
변수 캡슐화 하기
변수와 같은 데이터를 다룰 때 유효범위가 짧은 변수들은 대체로 문제를 일으키지 않지만, 전역변수 또는 public 필드와 같이 유효범위가 넓은 데이터들은 문제를 많이 일으키게 됩니다.
해당 문제를 해결하기 위해 캡슐화
를 진행 합니다.
캡슐화를 하여 특정 클래스의 데이터를 변경할 때에는 개발자가 지정한 getter/setter
함수를 통해서만 수정할 수 있게 합니다. 이렇게 하면 데이터를 변경하고 사용하는 코드를 감시할 수 있는 확실한 통로가 되어주기 때문에 데이터 변경 전 검증이나 변경 후 추가 로직을 쉽게 끼워넣을 수 있습니다.
제 첫 포폴을 만들 때 하고싶은건 많고 시간은 촉박하여 에라 모르겠다~ 하고 전부 public
필드로 다 떼려박았던 기억이 있습니다. 만들때는 쉬웠는데, 만들고 나서 버그가 발생하였을 때 데이터의 유효범위가 너무 넓어 디버깅이 어려운 문제점이 있었습니다. 결국 그 프로젝트는 끝내지 못했던걸로 기억합니다.
아마 여러 고수분들이 말하는 모든 필드들은 private
으로 선언해야 한다 라는것이 이러한 문제 때문이 아닐까 싶습니다. private
필드로 만들고 캡슐화하여 관리하도록 해야 합니다.
여기서, 생각해봐야 할 것이 유효범위가 넓은것만이 문제일까? 입니다. 물론 유효범위가 넓으면 디버깅할 때 생각해야하는 지점이 많아져 힘든것은 사실입니다. 하지만 여기에 한가지가 더 붙으면 정말 디버깅하기 어려운 코드가 탄생 합니다. 바로 가변 필드
입니다. 유효범위도 넓고, 데이터를 바꿀 수 있다면, 어우.. 생각만 해도 끔찍하군요.
그래서, 캡슐화를 하지 않으려면 해당 데이터를 불변
으로 만들어서 사용해야 합니다. 즉, 불변성은 강력한 방부제인 셈입니다.
해당 기법은 객체지향을 공부했다면 굉장히 기본적인 방법이기에, 예제는 생략합니다.
절차
- 변수로의 접근과 갱신을 전담하는 캡슐화 함수를 만든다.
- 정적 검사를 수행한다.
- 변수를 직접 참조하던 부분을 모두 적절한 캡슐화 함수 호출로 바꾼다. 하나씩 바꿀 때마다 테스트 한다.
- 변수의 접근 범위를 제한한다.
- 테스트한다.
- 변수 값이 레코드라면 레코드 캡슐화하기를 적용할지 고려해본다.
변수 이름 바꾸기
함수를 만들다 보면, 매개변수를 많이 만들어야 할 때가 있습니다. 예를들어, 데이터베이스에 접근하여 유저 데이터를 삽입하는 함수가 있다고 생각해봅시다. 유저의 데이터는 Name
, Age
, PhoneNumber
, Address
등등이 있다고 가정합니다. 이 정보들을 받으려면 벌써 매개변수가 4개가 됩니다.
function insertUser(name, age, phoneNumber, address) {
//insert 로직
}
제가 예전에 재고관리 프로그램을 짤 때 위와같이 코드를 짰습니다. 이렇게하니까 빠지는데이터도 생기고, 해당 매개변수 사이에 다른 매개변수가 끼면 이 데이터들이 무슨역할을 하는거였지? 라고 헷갈릴때도 많았습니다.
이런경우, 데이터들을 담고있는 클래스들을 만들어서 매개변수로 받게 만듭니다.
function insertUser(user) {
//insert 로직
}
class User {
constructor(name, age, phoneNumber, address) {
this.name = name;
this.age = age;
this.phoneNumber = phoneNumber;
this.address = address;
}
}
이렇게 하면, 데이터 사이의 관계가 명확해진다는 이점을 얻습니다. 게다가 매개변수 수가 줄어들어 코드를 읽기 더 쉬워집니다.
절차
- 적당한 데이터 구조가 아직 마련되어 있지 않다면 새로 만든다.
- 테스트한다.
- 함수 선언 바꾸기로 새 데이터 구조를 매개변수로 추가한다.
- 테스트한다.
- 함수 호출 시 새로운 데이터 구조 인스턴스를 넘기도록 수정한다. 하나씩 수정할 때마다 테스트한다.
- 기존 매개변수를 사용하던 코드를 새 데이터 구조의 원소를 사용하도록 바꾼다.
- 다 바꿨다면 기존 매개변수를 제거하고 테스트한다.
여러 함수를 클래스로 묶기
안드로이드 앱 프로그래밍을 할 때, 했던 실수입니다. 마찬가지로 재고관리앱을 만들 때 벌어졌던 실수입니다. 재고관리앱에서 시간을 관리하는 함수, 데이터베이스에 접근하는 함수 등을 필요할 때마다 복사해서 클래스에 붙여 사용했던 기억이 있습니다. 이렇게하니, 하나의 엑티비티에 너무 많은 코드가 들어가게 되고, 시간관리 로직이 바뀔 때 마다 해당 함수들을 다 찾아서 바꿔줘야 하는 단점이 있었습니다.
같은 기능을 하는 함수들을 클래스로 모아서 사용한다 라는것이 지금은 너무나도 당연한데, 이때는 왜 그렇게 생각을 못했는지 모르겠습니다.
이 깨달음을 얻고 난 후, 어떤 프레임워크를 사용하던간에, 프레임워크에서 사용할 수 있는 공용함수, 해당 언어에서 사용하는 공용함수들을 모아서 관리하는 습관이 생기게 되었습니다.
여러 함수를 한번에 관리할 수 있다는 장점, 호출부에서는 별다른 로직없이 함수만을 호출하면 된다는 장점, 다른 프로젝트할때에 같은 로직을 다시 만들 필요가 없다는 장점, 하나의 클래스에서만 의존성을 주입하면 된다는 장점 등을 챙길 수 있었습니다.
해당 기법도 예제는 생략합니다.
절차
- 함수들이 공유하는 공통 데이터 레코드를 캡슐화 한다
- 공통 레코드를 사용하는 함수 각각을 새 클래스로 옮긴다.
- 데이터를 조작하는 로직들은 함수로 추출해서 새 클래스로 옮긴다.
댓글 남기기