개요
리팩터링은 결국 프로그램의 요소를 조작하는 것, 조작은 변수보다 함수가 더 쉽다.
함수는 변경 시 기존 함수에 전달 함수를 활용해 임시 버퍼 역할을 할 수도 있어 유연하다. (차후 기존함수명으로 변경)
반면에 변수는 한 번에 바꿔야 해서 더 까다롭다.
변수의 유효 범위가 좁으면 문제가 될 건 거의 없지만 넓어질수록 문제가 된다.
넓은 범위 변수는 함수로 데이터를 캡슐화하는 것이 가장 좋은 방법이다.
데이터 재구성 ==> 함수 재구성으로 변환
함수는 동작이기에 중간에 검증 같은 조직을 끼워 넣을 수 있다.
이러한 이유가 객체지향에서 객체 데이터를 최대한 private로 유지하는 이유다. (데이터에 대한 결합도를 떨어트리기 위함)
불변 데이터는 가변 데이터보다 캡슐화할 이유가 적다. 데이터가 변경될 일이 없어서 그냥 복사해서 사용하면 된다.
예시
let spaceship = {}; let defaultOwner = {firstName:"마틴",lastName:"파울러"}; //참조하는 코드 spaceship.owner = defaultOwner; //갱신하는 코드(불변이라면 갱신 걱정이 없다) defaultOwner = {firstName:"레베카",lastName:"파슨스"}; |
let spaceship = {}; let defaultOwner = {firstName:"마틴",lastName:"파울러"}; spaceship.owner = defaultOwner; defaultOwner = {firstName:"레베카",lastName:"파슨스"}; //게터/세터 생성 function getDefaultOwner(){return defaultOwner;} function setDefaultOwner(arg){return defaultOwner = arg;} |
let spaceship = {}; let defaultOwner = {firstName:"마틴",lastName:"파울러"}; //게터 호출, 대입문은 세터 호출 spaceship.owner = getDefaultOwner(); setDefaultOwner({firstName:"레베카",lastName:"파슨스"}); function getDefaultOwner(){return defaultOwner;} function setDefaultOwner(arg){return defaultOwner = arg;} |
let spaceship = {}; //접근 제한자가 없는 언어에서는 이런 식으로 표현하는 것도 도움된다. let __privateOnly_defaultOwner = {firstName:"마틴",lastName:"파울러"}; spaceship.owner = getDefaultOwner(); setDefaultOwner({firstName:"레베카",lastName:"파슨스"}); //저자는 자바스크립트에서는 게터에 get을 빼는 것을 선호함 function defaultOwner(){return __privateOnly_defaultOwner;} function setDefaultOwner(arg){return __privateOnly_defaultOwner = arg;} |
자바스크립트에선 게터와 세터 이름을 똑같이 짓고 인수 존재 여부로 구분하는 방식을 많이 쓰기때문에 get을 뺸 것
값 캡슐화하기
//test_refac.mjs import {defaultOwner} from './test_refac.mjs'; import { strict as assert } from 'node:assert'; const owner1 = defaultOwner(); assert.equal("파울러",owner1.lastName,"처음 값 확인"); const owner2 = defaultOwner(); owner2.lastName ="파슨스"; assert.equal("파슨스",owner2.lastName,"owner2 변경 후"); |
import {defaultOwner} from './test_refac.mjs'; import { strict as assert } from 'node:assert'; const owner1 = defaultOwner(); assert.equal("파울러",owner1.lastName,"처음 값 확인"); const owner2 = defaultOwner(); owner2.lastName ="파슨스"; console.log(owner1); assert.equal("파슨스",owner1.lastName,"owner2 변경 후"); console.log(owner1); ////// 객체 값이 변경된 것을 볼 수 있다. Debugger attached. { firstName: '마틴', lastName: '파슨스' } { firstName: '마틴', lastName: '파슨스' } Waiting for the debugger to disconnect… |
let spaceship = {}; let defaultOwnerData = {firstName:"마틴",lastName:"파울러"}; spaceship.owner = defaultOwner(); //방법1 게터에서 객체 복사본을 리턴한다. export function defaultOwner(){return Object.assign({},defaultOwnerData);} export function setDefaultOwner(arg){defaultOwnerData = arg;} 결과 클라이언트에서 오히려 원본을 원하는 경우를 주의해야 한다. |
let defaultOwnerData = {firstName:"마틴",lastName:"파울러"}; //방법 2 레코드 캡슐화하기 export function defaultOwner(){return new Person(defaultOwnerData);} export function setDefaultOwner(arg){defaultOwnerData = arg;} class Person{ constructor(data){ this._lastName = data.lastName; this._firstName = data.firstName; } get lastName(){return this._lastName;} get firstName(){return this._firstName;} } |
경우에 따라 세터도 복사본을 저장하는게 좋을 수도 있다.
복제가 성능에 주는 영향을 미미하다. 반면에 원본을 그대로 사용하면 나중에 디버깅하기 어렵고 시간도 오래 걸릴 위험이 있다.
'IT책, 강의 > 리팩터링' 카테고리의 다른 글
06 - 기본적인 리펙터링 - 변수 이름 바꾸기 (0) | 2023.07.21 |
---|---|
06 - 기본적인 리펙터링 - 매개변수 객체 만들기 (0) | 2023.07.20 |
06 - 기본적인 리펙터링 - 함수 선언 바꾸기 (0) | 2023.07.18 |
06 - 기본적인 리펙터링 - 변수 인라인하기 (0) | 2023.07.17 |
06 - 기본적인 리펙터링 - 변수 추출하기 (0) | 2023.07.16 |