전체 글
Java 리팩토링 - 상속을 위임으로 바꾸기 (Replace Inherit with Delegate)
1. 알고자 하는 것 객체지향에서 상속은 기존 기능을 재사용할 수 있는 강력한 기능을 제공한다. 하지만 상속에도 단점이 존재하며, 상속이 적절치 않은 경우가 존재한다. 이럴 때 상속을 위임(Delegate) 으로 바꾸어 해결할 수 있다. 상속을 위임으로 바꾸기 (Replace Inherit with Delegate) 2. 알게 된 것 상속은 상위 클래스의 기능을 하위 클래스가 재사용 할 수 있는 좋은 방법이다. 상속으로 불필요한 코드의 중복을 막을 수 있고, 공통 기능의 변경 시 변경점이 줄어든다. 하지만 이러한 상속이 적절하지 않은 경우가 존재한다. 상속 받는 하위 클래스의 경우 상위 클래스의 모든 기능을 지원해야 한다. 자바의 Stack 클래스의 경우, Vector를 상속 받는다. 상위 클래스인 Ve..
Java 리팩토링 - 특이 케이스 추가하기 (Introduce Special Case)
1. 알고자 하는 것 여러 메서드에서 특정 데이터를 기준으로 계속 로직이 분기된다면, 이를 아예 클래스로 분리해 코드의 길이를 대폭 줄일 수 있다. 그리고 그 중심에는 다형성이 있다. 무궁무진한 다형성의 활용도를 익히기 위해 더 열심히 공부해야겠다는 괜한 동기부여가 되는 주제인 것 같다. 특이 케이스 추가하기 (Introduce Special Case) 2. 알게 된 것 위에서 말한 "특정 데이터를 기준으로 계속 로직이 분기" 되는 상황을 특이 케이스 (Special Case)라고 정의할 수 있다. 가령, 다음과 같은 형식이다. public class Customer { private String name; private BillingPlan billingPlan; private PaymentHistor..
Java 리팩토링 - 기본형을 객체로 바꾸기 (Replace Primitive with Object)
1. 알고자 하는 것 기본은 중요하다. 하지만 코드에서 기본형(Primitive Type)은 언제나 좋지만은 않다. 필요한 기능들이 많아지면 기본형만으로는 부족한 때가 온다. 기본형만으로는 버거울 때, 어떻게 해야할까 기본형을 객체로 바꾸기 (Replace Primitive with Object) 2. 알게 된 것 특정 데이터는 초기의 개발에는 기본형(Primitive Type) 만으로 충분히 표현 가능할 수 있다. 하지만 기능이 변경되고 추가됨에 따라, 이러한 데이터를 기반으로 수행해야 하는 기능이 추가될 수 있다. (ex. type에 올바른 값이 들어오는지 validation / type의 우선순위 비교) 이 경우 기본형을 그대로 사용해 추가된 기능을 구현할 수 있지만, 코드가 직관적이지 못하고 기본..
Java 리팩토링 - 함수 인라인, 클래스 인라인 (Function Inline, Class Inline)
1. 알고자 하는 것 이전에 함수 추출하기(Extract Method) 글을 통해 코드의 내용에 직관적인 이름을 붙여 가독성을 높일 수 있다고 학습한 적이 있었다. 이러한 추출하기 기법은 함수 뿐 아니라 클래스 단위로도 가능하며, 마찬가지로 클래스로 코드의 내용을 추출해 직관적으로 코드의 가독성을 높이고 응집도를 높일 수 있다. 하지만 함수/클래스 추출하기와 반대로, 때로는 함수/클래스로 추출했던 코드를 다시 본문 코드에 옮겨넣는 것이 코드의 가독성을 높일 수 있는 상황이 있다. 이러한 리팩토링 방법을 함수/클래스 인라인 (Function / Class Inline) 이라고 한다. 함수 인라인 (Function Inline) 클래스 인라인 (Class Inline) 2. 알게 된 것 함수/클래스 추출하기..
Java 리팩토링 - 함수 옮기기 (Move Function)
1. 알고자 하는 것 프로그램을 작성할 때 모듈화가 잘 된 소프트웨어는 최소한의 지식만으로 프로그램을 변경할 수 있다. 즉, A 도메인의 기능을 변경하기 위해 최소한의 코드만을 살펴볼 수 있도록 되어 있다면 모듈화가 잘 되어있는 것이다. 반대로, A 도메인의 기능을 변경하기 위해 여러 클래스, 여러 코드를 봐야 이해할 수 있다면 모듈화가 잘 되어있지 않은 것이다. 비슷한 문맥의 코드가 응집되어 있지 않고 여러 곳에 흩어져 있고 (응집도가 낮음), 불필요하게 여러 문맥 간 서로 의존하고 있어 하나의 변경점에 대해서 의존성이 묶여있는 여러 코드가 함께 변경되어야 한다면 (의존성 높음) 모듈화가 잘 되어있지 않은 것이다. 높은 모듈화를 통해 하나의 변경사항에 대해 최소한의 코드 파악과 최소한의 코드 수정으로 ..
[Real MySQL, 6장 - 실행계획] type 컬럼 분석
1. 알고자 하는 것 쿼리의 실행계획에서 type 컬럼은 MySQL 서버가 테이블의 레코드를 어떤 방식을 사용해 읽어왔는지를 의미한다. type 컬럼에 따라 쿼리의 성능과 튜닝 필요 여부를 판단할 수 있다. 실행계획의 type 컬럼 비교 2. 알게 된 것 type은 const > eq_ref > ref > ref_or_null > unique_subquery > index_subquery > index > ALL 순으로 성능이 빠르다. 각 실행계획의 성능 순서대로 알아보도록 한다. const WHERE 절에 PK 또는 유니크 컬럼을 동등 조건(=)으로 사용할 때 (결과가 반드시 1건일 때) 타 DBMS에서는 이를 유니크 인덱스 스캔(UNIQUE INDEX SCAN)이라고 한다. type 중 속도가 가장 ..
Java 리팩토링 - 변수 캡슐화하기 (with. Getter/Setter)
1. 알고자 하는 것 자바를 통해 개발을 하면서 클래스 내 필드를 변경하거나 가져올 때 주로 Getter, Setter를 많이 사용한다. Getter, Setter를 통해 필드를 캡슐화 함으로써 다양한 곳에서의 추적 불가능한 값의 변경을 막기 위해 사용하는 정도로만 이해하고 있었다면 이 내용을 통해 한 단계 더 깊게 알아보자. 변수 캡슐화하기 (Encapsulate Variable) 2. 알게 된 것 클래스 내 가지고 있는 변수는 말 그대로 상황에 따라 변경 되는 값이다. 특정 조건에 따라서 필드값이 변경되어야 하는 등의 상황이 그 예시에 속한다. 그 변수는 클래스 내 인스턴스 변수일 수도 있고, 클래스 변수일 수도 있다. 이 때, 단순히 변수를 public으로 열어두고 모든 곳에서 변경이 쉽게 가능하게..
[MySQL] GROUP_CONCAT으로 grouping 한 결과를 한줄로 출력하기
1. 알고자 하는 것 회사에서 특정 조건으로 데이터를 2개의 그룹으로 그룹핑해서 추출하고, 이를 각각 일괄적으로 업데이트 해야하는 일이 있었다. 즉, 다음과 같은 형태이다. 이 때, 여러 데이터에 대해 콤마(,)로 구분지어 입력값을 넣으면 일괄적으로 업데이트를 처리할 수 있도록 팀 내에서 유틸성 기능을 Admin Page에서 제공하고 있었고, 이로 인해 특정 컬럼으로 그룹핑 된 n개의 데이터를 콤마로 구분지어 추출해야 했다. 이 때 유용하게 활용했던 GROUP_CONCAT 기능을 알아본다. GROUP_CONCAT 2. 알게된 것 사용자(member)는 여러 물건(product)을 구매할 수 있다. 사용자 별로 구매한 물건을 그룹핑해 콤마로 구분지어 출력해보자. member 테이블의 데이터는 다음과 같다...
Java 리팩토링 - 플래그 인수 제거하기
1. 알고자 하는 것 회사에서 코드를 작성할 때, Flag 변수를 생각보다 많이 사용했다는 것을 이번 강의를 보고 느끼게 되었다. 단순히 private 메서드 개수를 줄이기 위해 / 공통 메서드로 묶기 위해 Flag 변수를 두어 메서드 하나에서 로직을 분기했었다. 내 딴에서는 공통로직의 재사용이라는 리팩토링 명목으로 사용한 Flag 변수였지만, 이번 강의를 통해 '단순히 라인 수를 줄이는 것이 리팩토링이 아니다' 라는 의미를 한번 더 깨닫게 된 것 같다. 리팩토링은 '짧은 코드를 만드는 것'이 목적이 아니라 '의도를 명확히 / 가독성을 좋게' 하는 것이 목적임을 늘 상기하자! 플래그 인수 제거하기 2. 알게된 것 boolean, enum 타입과 같은 Flag 변수를 통해 함수 내부의 로직을 분기하는 경우..
Java 리팩토링 - 조건문을 다형성으로 바꾸기
1. 알고자 하는 것 조건문을 다형성으로 바꾸기 (Replace Conditional with PolyMorphism) 2. 알게된 것 여러 타입에 따라 각각 다른 로직으로 처리해야 하는 경우, 일반적으로 중첩 if문으로 분기하거나, switch-case 문으로 분기하곤 한다. // if문 분기 if (Type.A) { A_Logic(); } else if (Type.B) { B_Logic(); } else { C_Logic(); } // switch문 분기 switch(Type) { case A -> { A_Logic(); } case B -> { B_Logic(); } case C -> { C_Logic(); } } 하지만, 만약 타입 간 공통으로 사용되는 로직이 많고, 타입에 따라 일부분의 로직만 ..