[ Programming ]
Refactoring
- API 리팩터링
[리팩터링] API 리팩터링
API 리팩터링 모듈과 함수는 소프트웨어를 구성하는 빌딩 블록이다. API는 이 블록들을 끼워 맞추는 연결부다. 그래서 API는 이해하고 사용하기 쉽게 만드는 일이 중요하다. 물론 어렵지만 API를 개선 한느 방법을 새로 깨달을 때마다 그에 맞게 리팩터링 해야한다. 이번 장에서는 API를 리팩터링 하는 방법들을 소개하려고 한다. API 리팩터링 방법 예시들을 소개하려고 한다. 1.1 질의 함수와 변경 함수 분리하기 좋은 API는 데이터 갱신과 조회를 명확히 구분해야한다. 그래야 겉보기 효과가 부수효과 없이 이해와 일치하기 때문이다. 예를 들면 조회 함수(get)을 사용하는데 부수효과로 데이터를 바꾸면(set) 테스트도 힘들도 신경 쓸 거리가 많아진다. 이를 명령-질의 분리라고도 하는데, 항상 100% 따르기는 힘들 수도 있지만 이 원칙을 왠만하면 지키는 것이 좋다. 이제 예시를 보겠다. // 찾고 알람 울리는 함수. function alertForMiscreant(people) { for (const p of people) { if(p === "조커") { setOffAlarms(); return "조커"; } if(p === "사루만") { setOffAlarms(); return "사루만"; } } return ""; } // 사이드 이펙트 제거 function findMiscreant (people) { for (const p of p...2025-09-09 - 리팩터링
[리팩터링] 조건부 로직 간소화
[리팩터링] 조건부 로직 간소화 조건부 로직은 자주 쓰이지만 프로그램을 복잡하게 만드는 주요 원인 중 하나다. 그래서 이번 장에서는 조건부 로직을 가독성있고 유지 보수성있게 만드는 방법을 알려주고자 한다. 1.1 조건문 분해하기 다양한 조건에 따라 동작도 다양한 코드를 작성하면 긴 함수가 만들어진다. 그래서 조건에 따른 동작을 표현한 코드는 "무슨 일이 일어나는 지"와 "왜 일어나는 지"를 말해줘야 가독성이 좋아진다. 간단히 말하면 코드를 부위별로 분해하고, 각 부위를 의도를 살린 이름의 함수 호출로 바꾸는 작업이다. 아래는 계절이 여름이면 할인율이 달라지는 예시 코드에 조건문 분해하기를 적용한 예시다. // 리팩터링 전 여름에 할인율이 다른 코드 if(!aDate.isBefore(plan.summerStart) && !aDate.isAfter(plan.summerEnd)) { // 함수 추출 1 charge = quantity } else { charge = quantity } // 리팩터링 후 추상화 된 코드 => 여름이면 여름 요금을 계산하고 아니면 보통 요금을 계산한다 // 어떻게 => 무엇을 왜 했는지 더 잘 들어나게 됌. (기본 리팩터링편 글에서도 "어떻게" 보다 "목적"을 더 잘 들어내야 함을 강조했었다!!) if(summer()) { // charge = summerCharge(); // 2- } else { charge = regularCharge(); // 2- } function summer() {...}; function summerCharge()...2025-09-02 - 리팩터링기능 이동
[리팩터링] 기능 이동
[리팩터링] 기능 이동 지금 까지는 프로그램 요소를 생성 혹은 제거하거나 이름을 변경하는 리팩터링을 했다. 그리고 리팩터링 저자는 여기에 더해 요소를 다른 컨텍스트 (클래스 또는 모듈)로 옮기는 일도 중요한 축이라 한다. 그래서 "기능 이동" 글에서는 함수 옮기기, 필드 옮기기와 같은 리팩터링 방법을 소개하려고 한다. 1.1 함수 옮기기 소프트웨어 핵심의 설계는 모듈성이다. 모듈성은 프로그램을 수정할 때 해당 기능의 작은 일부만 이해해도 가능하게 해주는 능력이다. 리팩터링 저자에 따르면 모듈성을 높이는 방법은 "서로 연관된 요소들을 함께 묶고, 요소 사이의 연결 관계를 쉡기 찾고 이해할 수 있도록 만들기"이다. 그리고 프로그램을 얼마나 이해했느냐에 따라서 모듈성을 더 잘 높일 가능성이 증가하며 요소들을 이리 저리 옮겨야할 수 도 있다. 함수 옮기는 Case 어떤 함수가 속한 모듈 A의 요소들보다 모듈 B의 요소들을 더 많이 참조한다면, 이 함수를 모듈 B로 옮기면 이 소프트웨어는 모듈 B의 세부사항에 덜 의존하게 된다. (캡슐화가 개선된다.) 도우미 역할로 정의된 함수 중 독립적으로 고유한 가치가 있는 것은 접근하기 더 쉬운 장소로 옮긴다. (또는 다음 업데이트 때 바뀌리라 예상되는 위치에 따라서 옮긴다.) 사실 함수를 옮길지 말지를 정하기는 쉽지 않다. 저자에 따르면 그럴 땐 대상 함수의 현재 컨텍스트와 후보 컨텍스트를 둘러보면 도움이 된다. 그리고 함수 이동 뿐만이 아니라 연관된 함수들은 클래스 묶기나 클래스 추출하기로 해결하기도 한다. 그리고 함수의 최적의 장소를 찾기 어려운 경우에는 한 컨텍스트에 두고...2025-08-26 - 캡슐화리팩터링
[리팩터링] 캡슐화
[리팩터링] 캡슐화 리팩터링 저자에 따르면 모듈을 분리하는 가장 중요한 기준은 시스템에서 각 모듈이 자신을 제외한 다른 부분에 드러내지 않아야 할 비밀을 얼마나 잘 숨기느냐에 있다. 클래스는 본래 정보를 숨기는 용도로 설계되었고, 클래스는 내부 정보뿐 아니라 클래스 간의 연결 관계를 숨기는 데도 유용하다. 그리고 캡슐화의 가장 큰 단위는 클래스와 모듈이지만, 함수도 구현을 캡슐화한다. 오늘은 캡슐화 방법을 통해 어떻게 리팩터링해서 깔끔한 코드를 만들 수 있을지 함께 공부해서 좋은 코드를 만드는 것이 목표다. 레코드는 연관된 여러 데이터를 직관적인 방식으로 묶을 수 있어서 각각 따로 취급할 때보다 훨씬 의미있는 단위로 전달할 수 있게 해준다.그런데 단순한 레코드에는 단점이 있다. 계산해서 얻을 수 있는 값과 그렇지 않은 값을 명확히 구분해 저장해야 해서 번거롭다. 예를 들면 최종 세금같이 여러 상수들의 곱을 통해 최종 산출되는 값이 필요한 경우 번거로워 진다. 레코드 구조는 두가지로 구분할 수 있다. 필드명을 노출하는 형태와 필드를 외부로부터 숨겨서 원하는 이름을 쓰는 형태다. 예를들면 전자는 클래스같이 필드명이 노출되는 형태이고, 후자는 Map, HashMap, dictionary처럼 Map.get("키")와 같이 필드명이 노출되지 않는 형태다. 그런데 필드명을 노출하지 않는 형태는 불분명함이 크기때문에 필드명을 노출하는 형태가 선호된다. 1.1 레코드 캡슐화 절차 절차 레코드를 담은 변수를 캡슐화한다. (기본 리팩터링 6.1 변수 캡슐화 참고) 레코드를 감싼 단순한 클래스로 해당 변수의 내용을 교체한다. 이...2025-08-18 - 리팩터링
[리팩터링] 기본적인 리팩터링
[리팩터링] 기본적인 리팩터링 최근 Nextjs로 만든 블로그를 리팩터링하면서 만족스럽지 않은 것 같아 다시 리팩터링을 공부해보고자 한다. 나는 "어떤 자세를 취해야 할까??" 혹은 "어느 정도까지 리팩터링 원칙을 적용해야할까?" 혹은 "책에서는 리팩터링이 성능을 낮추지만 리팩터링 후에는 오히려 성능 튜닝하기 편해진다는 식으로 말했었는데 과연 그런 여유를 가지며 리팩터링 할 수 있을까??"와 같은 생각을 자주 한다. 현업에서도 상황에 따라 적정선이 많이 달라지는 것 같다는 생각을 많이 했었고 결국 모든 것은 트레이드오프 관계로 이루어진다는 것이 현재 나의 생각이다... 이런 막연한 생각 말고 좀 더 구체적으로 상황에 따른 해법을 제시할 수 있으면 좋겠다. 그래서 내가 만든 컴포넌트 중 엉망인 부분을 리팩터링 책에 나온 기본적인 리팩터링을 적용하면 어떻게 느껴질지 실험해보고자 한다. 물론 시간이 많이 걸려서 책에 있는 예시도 많이 사용할 예정이다. 함수 호출하기는 인라인 코드를 별도로 함수로 만들어 호출하는 것을 의미한다. 함수(function) 추출하기에서 함수는 객체 지향 언어의 메서드(method)나 절차형 언어의 프로시저(procedure)나 서브루틴(subroutine)이라고 보고 똑같이 적용하면 된다. 코드를 "언제 함수로 묶어야 할까?"라는 기준은 너도 나도 다르다. 그 기준은 길이가 될 수 있고, 화면을 기준으로 될 수 있고, 재사용성을 기준으로 둘 수 있다. 리팩터링 책 저자는 "목적과 구현을 분리"하는 방식이 가장 합리적인 기준으로 본다. 개인 적인 해석으로는 추상화라고 생각한다. 구현한 코드...2025-08-12