5주차 Unit 4.2 — 1단계: 메서드 추출 (getConnection)

Psj·2026년 5월 27일

F-lab

목록 보기
167/239

Unit 4.2 — 1단계: 메서드 추출 (getConnection)

F-LAB JAVA · 5주차 · Phase 4 · 관심사의 분리
★ 깊이 파기 — 리팩토링 1단계


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • 메서드 추출 (Extract Method) 이란?
  • Before (중복) → After (추출) 의 변화는?
  • getConnection 메서드 추출 의 효과는?
  • 중복 제거의 이점 은?
  • DB 정보 변경 시 수정 범위 변화 는?
  • 적용된 SOLID 원칙 은?
  • 메서드 추출의 한계 는?
  • 아직 남은 문제 (다른 DB 지원) 는?
  • 다음 단계 (추상화) 의 필요성 은?

🎯 핵심 한 문장

메서드 추출 (Extract Method) 은 여러 메서드에 중복된 코드를 하나의 메서드로 모으는 리팩토링으로, 반복되는 DB 연결 코드를 getConnection() 으로 추출하면 중복이 제거되고 DB 정보 변경 시 한 곳만 수정하면 된다.
추출 전에는 add·get·update 등 모든 메서드가 각자 드라이버 로딩과 연결 생성 코드를 반복했지만, 추출 후에는 getConnection() 한 메서드가 그 책임을 맡고 나머지 메서드는 이를 호출만 한다.
이로써 중복이 제거 되고, DB 접속 정보가 바뀌면 getConnection() 한 곳만 수정 하면 되어 "변경 1번 = 수정 N곳" 문제가 "변경 1번 = 수정 1곳" 으로 줄어든다.
이 단계는 SOLID 의 DRY 와 SRP 를 부분적으로 달성하지만, 아직 한계가 있다 — getConnection() 이 여전히 같은 클래스 안에 있어 고객사마다 다른 DB 연결 방식 을 지원하려면 코드를 수정해야 한다.
따라서 다음 단계에서는 getConnection() 을 추상 메서드 로 만들어 서브클래스가 연결 방식을 결정하게 한다 (Unit 4.3).

비유 — 공통 준비 작업 한 곳에

메서드 추출 = 공통 준비 한 곳에:

추출 전 (요리사마다 준비):
  - 김치찌개 요리사: 불 켜고, 냄비 꺼내고...
  - 된장찌개 요리사: 불 켜고, 냄비 꺼내고... (중복)
  - 부대찌개 요리사: 불 켜고, 냄비 꺼내고... (중복)

추출 후 (준비 담당 한 명):
  - 준비 담당: 불 켜고 냄비 준비 (getConnection)
  - 각 요리사: "준비된 것 주세요" (호출)

효과:
  - 준비 방식 바뀌면 (가스 → 인덕션)
  - 준비 담당만 바꿈 (한 곳)
  - 요리사들은 그대로

한계:
  - 준비 담당이 여전히 같은 주방
  - 다른 주방 방식 (고객사 DB) 못 함
  → 준비를 외부에 맡겨야 (다음 단계)

→ 메서드 추출 = 중복을 한 메서드로, DB 변경 = 한 곳, 하지만 다른 DB 한계.


🧭 9개 섹션 로드맵

1. 메서드 추출이란
2. Before — 중복
3. After — 추출
4. 중복 제거의 이점
5. 변경 범위 변화
6. 적용된 SOLID
7. 메서드 추출의 한계
8. 남은 문제와 다음 단계
9. 면접 + 자기 점검

1️⃣ 메서드 추출이란

1.1 메서드 추출

메서드 추출 (Extract Method):

  중복되거나 의미 있는 코드를
  별도 메서드로 분리.

  - 중복 제거
  - 의미 명확화
  - 재사용

1.2 리팩토링 기법

대표 리팩토링 기법:

  - Extract Method (메서드 추출)
  - Extract Class (클래스 추출)
  - Rename (이름 변경)
  - Move (이동)

  메서드 추출 = 가장 기본

1.3 추출 대상

추출 대상:

  - 중복된 코드
  - 긴 메서드의 일부
  - 의미 있는 묶음

  DAO: 연결 생성 코드

1.4 효과

메서드 추출 효과:

  - 중복 제거 (DRY)
  - 한 곳 관리
  - 의미 부여 (이름)
  - 재사용

1.5 ILIC 의 맥락

// 추출 대상: 반복되는 연결 코드
public class ShipmentDao {
    public void add(Shipment s) throws Exception {
        // 이 부분이 중복 (추출 대상)
        Class.forName("com.mysql.jdbc.Driver");
        Connection c = DriverManager.getConnection(
            "jdbc:mysql://localhost/ilic", "root", "password");
        // SQL...
    }
    // get, update 등에도 같은 코드 (중복)
    // → getConnection() 으로 추출
}

1.6 자기 점검 답변

메서드 추출 (Extract Method) 이란?

:
1. 추출:

  • 코드를 별도 메서드로
  1. 리팩토링:

    • 가장 기본 기법
  2. 대상:

    • 중복, 의미 있는 묶음
  3. 효과:

    • 중복 제거, 재사용

2️⃣ Before — 중복

2.1 중복 코드

// Before — 각 메서드가 직접 연결
public class ShipmentDao {
    
    public void add(Shipment shipment) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");        // 중복
        Connection c = DriverManager.getConnection(     // 중복
            "jdbc:mysql://localhost/ilic", "root", "password");
        PreparedStatement ps = c.prepareStatement(
            "insert into shipments(id, bl_no, weight) values(?, ?, ?)");
        ps.setLong(1, shipment.getId());
        ps.executeUpdate();
        ps.close();
        c.close();
    }
    
    public Shipment get(Long id) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");        // 중복
        Connection c = DriverManager.getConnection(     // 중복
            "jdbc:mysql://localhost/ilic", "root", "password");
        PreparedStatement ps = c.prepareStatement(
            "select * from shipments where id = ?");
        ps.setLong(1, id);
        ResultSet rs = ps.executeQuery();
        Shipment shipment = null;
        if (rs.next()) {
            shipment = mapRow(rs);
        }
        rs.close();
        ps.close();
        c.close();
        return shipment;
    }
    
    private Shipment mapRow(ResultSet rs) throws SQLException {
        Shipment s = new Shipment();
        s.setId(rs.getLong("id"));
        return s;
    }
}

2.2 중복 식별

중복 식별:

  add 와 get 의 공통:
    Class.forName("com.mysql.jdbc.Driver");
    Connection c = DriverManager.getConnection(
        "jdbc:mysql://localhost/ilic", "root", "password");

  → 완전히 동일 (추출 대상)

2.3 중복의 문제

중복의 문제:

  - DB 정보 변경 → 모든 메서드
  - 같은 코드 반복
  - 가독성 ↓
  - 유지보수 ↓

2.4 자기 점검 답변

Before (중복) 의 모습은?

:
1. 중복:

  • 각 메서드 연결 코드
  1. 공통:

    • 드라이버 + 연결
  2. 문제:

    • DB 변경 시 모두 수정
  3. 추출 대상:

    • 연결 코드

3️⃣ After — 추출

3.1 추출 후 코드

// After — getConnection 추출
public class ShipmentDao {
    
    // 추출된 연결 메서드 (한 곳)
    private Connection getConnection() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection(
            "jdbc:mysql://localhost/ilic", "root", "password");
    }
    
    public void add(Shipment shipment) throws Exception {
        Connection c = getConnection();   // 추출 메서드 호출 (깔끔)
        PreparedStatement ps = c.prepareStatement(
            "insert into shipments(id, bl_no, weight) values(?, ?, ?)");
        ps.setLong(1, shipment.getId());
        ps.executeUpdate();
        ps.close();
        c.close();
    }
    
    public Shipment get(Long id) throws Exception {
        Connection c = getConnection();   // 추출 메서드 호출 (깔끔)
        PreparedStatement ps = c.prepareStatement(
            "select * from shipments where id = ?");
        ps.setLong(1, id);
        ResultSet rs = ps.executeQuery();
        Shipment shipment = null;
        if (rs.next()) {
            shipment = mapRow(rs);
        }
        rs.close();
        ps.close();
        c.close();
        return shipment;
    }
    
    private Shipment mapRow(ResultSet rs) throws SQLException {
        Shipment s = new Shipment();
        s.setId(rs.getLong("id"));
        return s;
    }
}

3.2 변화

변화:

전:
  add, get 마다 연결 코드

후:
  getConnection (한 곳)
  add, get → getConnection() 호출

→ 중복 제거

3.3 깔끔해진 메서드

깔끔해진 메서드:

  add 메서드:
    - 연결 코드 사라짐
    - SQL 에 집중
    - 읽기 쉬움

  → 관심사 (SQL) 명확

3.4 자기 점검 답변

After (추출) 의 변화는?

:
1. 추출:

  • getConnection 한 곳
  1. 변화:

    • 메서드들이 호출만
  2. 깔끔:

    • SQL 에 집중
  3. 중복:

    • 제거됨

4️⃣ 중복 제거의 이점

4.1 이점 정리

중복 제거 이점:

1. 한 곳 관리
2. 변경 한 곳
3. 가독성
4. 재사용
5. 정합성

4.2 한 곳 관리

한 곳 관리:

  연결 코드:
    - getConnection 한 곳
    - 변경 시 여기만
    - 명확

4.3 가독성

가독성:

전 (add):
  드라이버 + 연결 + SQL + 해제
  (복잡, 핵심 안 보임)

후 (add):
  getConnection() + SQL + 해제
  (SQL 핵심 명확)

4.4 재사용

재사용:

  getConnection:
    - add, get, update, delete 모두 사용
    - 한 메서드 공유
    - DRY

4.5 ILIC 의 맥락

public class ShipmentDao {
    
    // 한 곳 — 모든 메서드가 재사용
    private Connection getConnection() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection(
            "jdbc:mysql://localhost/ilic", "root", "password");
    }
    
    // 재사용 1
    public void add(Shipment s) throws Exception {
        Connection c = getConnection();
        // ...
    }
    
    // 재사용 2
    public Shipment get(Long id) throws Exception {
        Connection c = getConnection();
        return null;
    }
    
    // 재사용 3
    public void update(Shipment s) throws Exception {
        Connection c = getConnection();
        // ...
    }
    
    // 재사용 4
    public List<Shipment> findByStatus(String status) throws Exception {
        Connection c = getConnection();
        return List.of();
    }
    // getConnection 한 곳, 4곳 재사용
}

4.6 자기 점검 답변

중복 제거의 이점은?

:
1. 한 곳 관리:

  • getConnection
  1. 변경 한 곳:

    • DB 정보
  2. 가독성:

    • SQL 명확
  3. 재사용:

    • 모든 메서드

5️⃣ 변경 범위 변화

5.1 변경 범위 축소

변경 범위 변화:

전: 변경 1번 = 수정 N곳
후: 변경 1번 = 수정 1곳

  DB 정보 변경:
    - getConnection 만

5.2 DB 변경 예시

// DB 비밀번호 변경
// 전: 모든 메서드 수정
// 후: getConnection 한 곳만

private Connection getConnection() throws Exception {
    Class.forName("com.mysql.jdbc.Driver");
    return DriverManager.getConnection(
        "jdbc:mysql://localhost/ilic", "root", 
        "new_password");   // 여기만 수정
}
// add, get, update ... 안 건드림

5.3 효과

효과:

  - 수정 비용 ↓ (1곳)
  - 실수 ↓ (한 곳)
  - 누락 X (한 곳)
  - 정합성 보장

5.4 여전한 한계

여전한 한계:

  DB 정보 변경: 1곳 (개선)

  하지만:
    - DB 종류 변경
    - 고객사별 다른 연결
    → getConnection 수정 (한계)

5.5 ILIC 의 맥락

public class ShipmentDao {
    
    // DB 접속 정보 변경 → 여기만
    private Connection getConnection() throws Exception {
        // 비밀번호 변경 → 이 줄만
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection(
            "jdbc:mysql://localhost/ilic",   // 서버 변경 → 이 줄만
            "ilic_user",                      // 계정 변경 → 이 줄만
            "secure_password");               // 비밀번호 변경 → 이 줄만
    }
    // 모든 데이터 접근 메서드는 영향 X
    // → 변경 1곳 (개선)
    
    // 단, DB 종류 (MySQL → Oracle) 는?
    // → getConnection 수정 (아직 한계)
    // → 다음 Unit (추상화)
}

5.6 자기 점검 답변

DB 정보 변경 시 수정 범위 변화는?

:
1. 축소:

  • N곳 → 1곳
  1. DB 변경:

    • getConnection 만
  2. 효과:

    • 수정 비용, 실수 ↓
  3. 한계:

    • DB 종류는 여전히 수정

6️⃣ 적용된 SOLID

6.1 DRY

DRY 적용:

  중복 제거:
    - 연결 코드 한 곳
    - 반복 X

  → DRY 달성

6.2 SRP (부분)

SRP 부분 달성:

  getConnection:
    - 연결 생성 책임만

  add, get:
    - SQL 책임 (연결은 위임)

  → 책임 약간 분리

6.3 아직 부족

아직 부족:

  SRP 완전 X:
    - getConnection 이 같은 클래스
    - 연결 + SQL 한 클래스

  OCP X:
    - DB 종류 변경 시 수정

  DIP X:
    - 여전히 구체 의존

6.4 점진적 개선

점진적 개선:

  Unit 4.2 (지금):
    - DRY, SRP 부분

  Unit 4.3:
    - 추상화 (OCP 향)

  Phase 6:
    - 인터페이스 (OCP, DIP)

6.5 ILIC 의 맥락

public class ShipmentDao {
    
    // DRY 달성 (중복 제거)
    // SRP 부분 (연결 책임 메서드 분리)
    private Connection getConnection() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection(
            "jdbc:mysql://localhost/ilic", "root", "password");
    }
    
    public void add(Shipment s) throws Exception {
        Connection c = getConnection();   // 연결 위임
        // SQL 책임만
    }
    
    // 아직:
    // - getConnection 이 같은 클래스 (SRP 부분만)
    // - DB 종류 변경 시 수정 (OCP X)
    // - 구체 의존 (DIP X)
    // → 다음 단계 개선
}

6.6 자기 점검 답변

적용된 SOLID 원칙은?

:
1. DRY:

  • 중복 제거
  1. SRP (부분):

    • 연결 메서드 분리
  2. 아직 부족:

    • OCP, DIP X
  3. 점진적:

    • 다음 단계 개선

7️⃣ 메서드 추출의 한계

7.1 한계

메서드 추출 한계:

  같은 클래스 안:
    - getConnection 이 ShipmentDao 내부
    - 연결 방식 고정
    - 변경 시 수정

7.2 DB 종류 변경

DB 종류 변경 한계:

  MySQL → Oracle:
    - getConnection 수정 필요
    - 기존 코드 변경 (OCP X)

7.3 고객사별 DB

고객사별 DB:

  "고객사마다 다른 DB"
    - getConnection 하나로 불가
    - 고객사별 다른 연결
    - 코드 수정 (한계)

7.4 코드 공개 문제

코드 공개 문제:

  "UserDao 코드는 공개하고 싶지 않다.
   그런데 고객사가 자기 DB 연결을 쓰게 하고 싶다"

  - getConnection 이 내부 → 고객사가 못 바꿈
  - 소스 수정 없이 연결 교체 불가

  → 추상화 필요

7.5 ILIC 의 맥락

public class ShipmentDao {
    
    private Connection getConnection() throws Exception {
        // MySQL 고정 (한계)
        Class.forName("com.mysql.jdbc.Driver");
        return DriverManager.getConnection(
            "jdbc:mysql://localhost/ilic", "root", "password");
    }
    
    // 한계 시나리오:
    // 1. 고객사 A: Oracle 사용 → getConnection 수정
    // 2. 고객사 B: PostgreSQL → 또 수정
    // 3. ShipmentDao 코드를 고객사에 공개 X
    //    → 고객사가 연결 못 바꿈
    
    // → getConnection 을 추상화해야
    // → 서브클래스/외부가 연결 결정 (다음 Unit)
}

7.6 자기 점검 답변

메서드 추출의 한계는?

:
1. 한계:

  • 같은 클래스 안
  • 연결 방식 고정
  1. DB 종류:

    • 변경 시 수정 (OCP X)
  2. 고객사별:

    • 하나로 불가
  3. 코드 공개:

    • 고객사가 못 바꿈

8️⃣ 남은 문제와 다음 단계

8.1 남은 문제

남은 문제:

1. DB 종류 변경 → 수정 (OCP X)
2. 고객사별 DB → 불가
3. 코드 공개 없이 교체 X
4. 구체 의존 (DIP X)

8.2 다음 단계 — 추상화

다음 단계 — 추상화:

  getConnection 을 추상 메서드로:
    - 흐름은 부모 (변하지 않음)
    - 연결은 자식 (변함)

  → 서브클래스가 연결 결정
  → Unit 4.3

8.3 추상화의 효과

추상화 효과:

  - DB 종류 = 새 서브클래스 (확장)
  - 부모 코드 변경 X (OCP 향)
  - 고객사가 서브클래스 작성

  → 한계 극복

8.4 진화 로드맵

진화 로드맵:

Unit 4.2 (지금): 메서드 추출
  - 중복 제거

Unit 4.3: 추상클래스
  - 서브클래스 연결

Phase 5: 디자인 패턴
  - 템플릿/팩토리

Phase 6: 인터페이스
  - OCP, 전략

Phase 7~8: IoC/DI
  - 외부 주입

8.5 ILIC 의 맥락

// 다음 단계 미리보기 (추상화)

// 현재 (Unit 4.2)
public class ShipmentDao {
    private Connection getConnection() throws Exception {
        // MySQL 고정
        return null;
    }
}

// 다음 (Unit 4.3) — 추상 메서드
public abstract class ShipmentDao {
    public void add(Shipment s) throws Exception {
        Connection c = getConnection();   // 변하지 않는 흐름
        // SQL...
    }
    
    public abstract Connection getConnection() throws Exception;  // 변하는 부분
}

// 고객사별 서브클래스
class MySqlShipmentDao extends ShipmentDao {
    public Connection getConnection() { return null; /* MySQL */ }
}
class OracleShipmentDao extends ShipmentDao {
    public Connection getConnection() { return null; /* Oracle */ }
}
// DB 종류 = 새 서브클래스 (부모 변경 X)

8.6 자기 점검 답변

아직 남은 문제와 다음 단계는?

:
1. 남은 문제:

  • DB 종류 변경 수정
  • 고객사별 불가
  1. 다음 단계:

    • 추상 메서드
  2. 효과:

    • 서브클래스 연결
    • OCP 향
  3. 로드맵:

    • 추상화 → 인터페이스 → DI

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
메서드 추출?코드를 별도 메서드
Before → After?중복 → 한 곳
getConnection 효과?중복 제거
중복 제거 이점?변경 한 곳, 재사용
변경 범위?N곳 → 1곳
적용 SOLID?DRY, SRP (부분)
한계?DB 종류 변경 수정
남은 문제?고객사별 DB, OCP
다음 단계?추상 메서드
진화?추상화 → DI

9.2 자기 점검 체크리스트

메서드 추출

  • 정의
  • 리팩토링

Before/After

  • 중복 → 추출

이점

  • 한 곳, 재사용

변경 범위

  • N → 1

SOLID

  • DRY, SRP

한계

  • DB 종류

다음 단계

  • 추상화

9.3 추가 심화 질문

Q1: IntelliJ 메서드 추출 단축키?

답:

  • Ctrl+Alt+M (Extract Method)
  • 코드 선택 후
  • 자동 추출
  • 안전한 리팩토링

Q2: 메서드 추출 vs 인라인?

답:

  • 추출: 코드 → 메서드
  • 인라인: 메서드 → 코드 (반대)
  • 추출: 중복/긴 메서드
  • 인라인: 불필요한 메서드

Q3: 추출 시 매개변수?

답:

  • 필요한 변수 → 매개변수
  • 결과 → 반환값
  • IDE 자동 처리
  • 의존성 명확

Q4: 너무 작은 메서드?

답:

  • 과도한 추출
  • 호출 추적 어려움
  • 적절한 단위
  • 의미 있는 묶음

Q5: 리팩토링과 테스트?

답:

  • 테스트 있어야 안전
  • 동작 보존 확인
  • 리팩토링 = 동작 불변
  • 테스트 → 리팩토링 → 테스트

🎯 핵심 요약 — 3줄 정리

1. 메서드 추출

  • 중복된 연결 코드를 getConnection() 으로
  • 중복 제거, 한 곳 관리

2. 변경 범위

  • DB 정보 변경: N곳 → 1곳
  • DRY, SRP (부분) 달성

3. 한계

  • DB 종류 변경 시 여전히 수정 (OCP X)
  • 고객사별 DB 불가 → 추상화 필요 (다음 Unit)

📚 다음으로...

Unit 4.3 — 2단계: 추상클래스로 확장 (다른 DB 지원)

이번 Unit에서 메서드 추출을 봤다면, 다음은 추상클래스 확장 (Phase 4 마지막).

  • getConnection 을 추상 메서드로
  • 변하지 않는 흐름 + 변하는 부분
  • 서브클래스가 연결 결정
  • 단일 상속의 한계

Phase 4 진행 상황

🌱 Phase 4 — 관심사의 분리 (★ 깊이)
  ✅ Unit 4.1 관심사 분리 개념
  ✅ Unit 4.2 1단계: 메서드 추출 ← 여기
  ⏭ Unit 4.3 2단계: 추상클래스로 확장

5주차 누적 진행

✅ Part A — 동시성 마무리 (7 Unit)
🌱 Part B — 토비의 스프링
  ✅ Phase 3 — 전통 DAO (3 Unit)
  🌱 Phase 4 — 관심사의 분리 (2/3, ★ 깊이)

총: 12/26 Unit
profile
Software Developer

0개의 댓글