[Refactoring] 1. 이해하기 힘든 이름

2025. 1. 2. 15:40·ETC
728x90
반응형

이해하기 힘든 이름 (Mysterius Name)

  • 깔끔한 코드에서 가장 중요한 것 중 하나가 바로 "좋은 이름"
    • 좋은 이름은 코드를 이해하는 데에 많은 도움을 준다
  • 함수, 변수, 클래스, 모듈의 이름 등 모두 어떤 역할을 하는지 어떻게 쓰이는지 직관적이어야 함
  • 처음에 적절하다고 생각했던 이름도 시간이 지나고 보면 그렇지 않게 보일 수 있으며, 이는 매우 자연스러운 현상이다
  • 사용할 수 있는 리팩토링 기술
    • 함수 선언 변경하기(Change Function Declaration)
    • 변수 이름 바꾸기(Rename Variable)
    • 필드 이름 바꾸기(Rename Field)

함수 선언 변경하기(Change Function Declaration)

  • 좋은 이름을 가진 함수는 함수가 어떻게 구현되었는지 코드를 보지 않아도 이름만 보고도 이해 할 수 있음
    • 구현부를 보지 않고도 선언부만 보고 이해 가능해야 함
  • 좋은 이름을 찾아내는 방법: 함수에 주석을 달고, 주석을 함수 이름으로 만들어 보기
  • 함수의 매개변수는
    • 함수 내부의 문맥을 결정
      • ex) 전화번호 포매팅 함수가 있다고 하면, 이 함수에 딱 '전화번호 텍스트'만 넘겨줄 것인지, 전화번호를 갖는 'Person'이라는 객체를 넘겨줄 것인지에 따라 함수 내부 문맥이 달라짐
      • 전화번호만 넘겨주는 경우 다른 곳에서 재사용하기는 편해지지만 기능은 단순해짐
      • Person을 넘기는 경우 해당 Person의 국가 정보를 참고해서 국가에 맞는 포매팅으로 전화번호를 변경해주는 것과 같은 기능이 가능해지지만 재사용성이 떨어짐
    • 의존성을 결정
      • ex) Payment 만기일 계산 함수가 있다고 할 때, Payment를 넘겨줄 수도 있고 Payment의 dueDate만 넘겨줄 수도 있다.
      • Payment 만기일 계산 시 Payment가 가지고 있는 타입이나 여러가지 속성들을 참조해야 된다면 Payment라는 타입을 넘겨주는 것이 맞을 것
      • dueDate만 필요하다면 dueDate만 넘겨주는 것이 맞을 것
      • => 정답은 없음
public class StudyDashboard {

    private Set<String> usernames = new HashSet<>();

    private Set<String> reviews = new HashSet<>();

    /**
     * 스터디 리뷰 이슈에 작성되어 있는 리뷰어 목록과 리뷰를 읽어온다
     * @param issue
     * @throws IOException
     */
    private void studyReviews(GHIssue issue) throws IOException {
        List<GHIssueComment> comments = issue.getComments();
        for (GHIssueComment comment : comments) {
            usernames.add(comment.getUserName());
            reviews.add(comment.getBody());
        }
    }

    public Set<String> getUsernames() {
        return usernames;
    }

    public Set<String> getReviews() {
        return reviews;
    }

    public static void main(String[] args) throws IOException {
        GitHub gitHub = GitHub.connect();
        GHRepository repository = gitHub.getRepository("whiteship/live-study");
        GHIssue issue = repository.getIssue(30);

        StudyDashboard studyDashboard = new StudyDashboard();
        studyDashboard.studyReviews(issue);
        studyDashboard.getUsernames().forEach(System.out::println);
        studyDashboard.getReviews().forEach(System.out::println);
    }
}

 

위 코드에서 studyReviews는 주석의 내용처럼 깃허브의 스터디 리뷰 이슈에 작성되어 있는 리뷰어 목록과 리뷰를 읽어오는 기능을 하는 메서드이다. 기능을 생각했을 때, studyReviews라는 이름은 적절하지 않아보이므로 기능을 잘 반영할 수 있도록 loadReviews로 변경한다. (기능만 잘 반영하고 있다면 이름은 자유)

 

이번엔 파라미터에 대해 고민해보자.

 

loadReviews는 현재 GHIssue라는 깃허브 이슈 객체를 받고 있다. 하지만, 잘 생각해보면 리뷰를 해올 이슈는 "whiteship/live-study"라는 레포지토리의 30번 이슈로 이미 정해져 있고 바뀌지 않는다. 즉, 이를 따로 넘겨줄 필요가 없다.

 

이렇게 수정된 결과는 다음과 같다.

private void loadReviews() throws IOException {
    GitHub gitHub = GitHub.connect();
    GHRepository repository = gitHub.getRepository("whiteship/live-study");
    GHIssue issue = repository.getIssue(30);

    List<GHIssueComment> comments = issue.getComments();
    for (GHIssueComment comment : comments) {
        usernames.add(comment.getUserName());
        reviews.add(comment.getBody());
    }
}

변수 이름 바꾸기(Rename Variable)

  • 더 많이 사용되는 변수일수록 그 이름이 더 중요함
    • 람다식에서 사용하는 변수 vs. 함수의 매개변수
  • 다이나믹 타입을 지원하는 언어에서는 타입을 이름에 넣기도 함
  • 여러 함수에 걸쳐 쓰이는 필드 이름에느 더 많이 고민하고 이름을 짓는다
  • 람다식에서 사용되는 변수의 경우
    • 람다식은 굉장히 범위가 좁고, 그 안에 어떤게 들어있는지 이미 알고있는 경우가 많다
    • 때문에, 간추려서 쓰거나 한 글자로 줄여서 쓰기도 한다
    • 혹은, 변수 정의 없이 메서드 레퍼런스 형태를 사용하는 것도 바람직하다
  • 변수는 그 문맥에서 변수의 역할을 제대로 반영하는 이름을 가져야 한다
public class StudyDashboard {

    private Set<String> usernames = new HashSet<>();

    private Set<String> reviews = new HashSet<>();

    /**
     * 스터디 리뷰 이슈에 작성되어 있는 리뷰어 목록과 리뷰를 읽어옵니다.
     * @throws IOException
     */
    private void loadReviews() throws IOException {
        GitHub gitHub = GitHub.connect();
        GHRepository repository = gitHub.getRepository("whiteship/live-study");
        GHIssue issue = repository.getIssue(30);

        List<GHIssueComment> comments = issue.getComments();
        for (GHIssueComment comment : comments) {
            usernames.add(comment.getUserName());
            this.reviews.add(comment.getBody());
        }
    }

    public Set<String> getUsernames() {
        return usernames;
    }

    public Set<String> getReviews() {
        return reviews;
    }

    public static void main(String[] args) throws IOException {
        StudyDashboard studyDashboard = new StudyDashboard();
        studyDashboard.loadReviews();
        studyDashboard.getUsernames().forEach(name -> System.out.println(name));
        studyDashboard.getReviews().forEach(review -> System.out.println(review));
    }
}

 

위와 같은 코드가 있다고 했을 때, main 함수 내부의 람다식은 모두 메서드 레퍼런스로 대체하는 것이 바람직해보인다. 또한, loadReviews 함수 내에서 comments라는 변수는 comment가 맞긴하지만, 좀더 명확하게 의미를 보여줄 수 있도록 하기 위해 reviews라는 이름으로 대체하는 것이 더 적절해보인다.

 

public class StudyDashboard {

    private Set<String> usernames = new HashSet<>();

    private Set<String> reviews = new HashSet<>();

    /**
     * 스터디 리뷰 이슈에 작성되어 있는 리뷰어 목록과 리뷰를 읽어옵니다.
     * @throws IOException
     */
    private void loadReviews() throws IOException {
        GitHub gitHub = GitHub.connect();
        GHRepository repository = gitHub.getRepository("whiteship/live-study");
        GHIssue issue = repository.getIssue(30);

        List<GHIssueComment> reviews = issue.getComments(); // 이름 변경
        for (GHIssueComment comment : reviews) {
            usernames.add(comment.getUserName());
            this.reviews.add(comment.getBody());
        }
    }

    public Set<String> getUsernames() {
        return usernames;
    }

    public Set<String> getReviews() {
        return reviews;
    }

    public static void main(String[] args) throws IOException {
        StudyDashboard studyDashboard = new StudyDashboard();
        studyDashboard.loadReviews();
        studyDashboard.getUsernames().forEach(System.out::println); // 메서드 레퍼런스
        studyDashboard.getReviews().forEach(System.out::println); // 메서드 레퍼런스
    }
}

필드 이름 바꾸기(Rename Field)

  • Record 자료 구조의 필드 이름은 프로그램 전반에 걸쳐 참조될 수 있기 때문에 매우 중요
    • Record 자료 구조: 특정 데이터와 관련있는 필드를 묶어놓은 자료 구조
      • ex) 파이썬의 Dictionary, 또는 줄여서 dicts / C#의 Record
    • 자바 14버전부터 지원
    • 자바에서는 getter와 setter 메서드 이름도 필드의 이름과 비슷하게 간주할 수 있음

이전 코드를 다시 보자.

public class StudyDashboard {

    private Set<String> usernames = new HashSet<>();

    private Set<String> reviews = new HashSet<>();

    /**
     * 스터디 리뷰 이슈에 작성되어 있는 리뷰어 목록과 리뷰를 읽어옵니다.
     * @throws IOException
     */
    private void loadReviews() throws IOException {
        GitHub gitHub = GitHub.connect();
        GHRepository repository = gitHub.getRepository("whiteship/live-study");
        GHIssue issue = repository.getIssue(30);

        List<GHIssueComment> reviews = issue.getComments();
        for (GHIssueComment review : reviews) {
            usernames.add(review.getUserName());
            this.reviews.add(review.getBody());
        }
    }

    public Set<String> getUsernames() {
        return usernames;
    }

    public Set<String> getReviews() {
        return reviews;
    }

    public static void main(String[] args) throws IOException {
        StudyDashboard studyDashboard = new StudyDashboard();
        studyDashboard.loadReviews();
        studyDashboard.getUsernames().forEach(System.out::println);
        studyDashboard.getReviews().forEach(System.out::println);
    }
}

 

현재는 리뷰를 하는 유저의 이름들과 리뷰 내용이 서로 다른 Set으로 관리되고 있다. 이를 레코드를 사용하여 함께 관리하도록 변경해보자.

public record StudyReview(String reviewer, String review) {
}
public class StudyDashboard {

    private Set<StudyReview> studyReviews = new HashSet<>();

    /**
     * 스터디 리뷰 이슈에 작성되어 있는 리뷰어 목록과 리뷰를 읽어옵니다.
     * @throws IOException
     */
    private void loadReviews() throws IOException {
        GitHub gitHub = GitHub.connect();
        GHRepository repository = gitHub.getRepository("whiteship/live-study");
        GHIssue issue = repository.getIssue(30);

        List<GHIssueComment> reviews = issue.getComments();
        for (GHIssueComment review : reviews) {
            studyReviews.add(new StudyReview(review.getUserName(), review.getBody()));
        }
    }

    public Set<StudyReview> getStudyReviews() {
        return studyReviews;
    }

    public static void main(String[] args) throws IOException {
        StudyDashboard studyDashboard = new StudyDashboard();
        studyDashboard.loadReviews();
        studyDashboard.getStudyReviews().forEach(System.out::println);
    }
}
728x90
반응형

'ETC' 카테고리의 다른 글

[Refactoring] 3. 긴 함수  (2) 2025.01.02
[Refactoring] 2. 중복 코드  (2) 2025.01.02
[오브젝트 - 기초편] 변경과 설계  (2) 2024.12.31
[오브젝트 - 기초편] 책임 할당하기  (2) 2024.12.30
[오브젝트 - 기초편] 객체지향 기본 원칙  (2) 2024.12.30
'ETC' 카테고리의 다른 글
  • [Refactoring] 3. 긴 함수
  • [Refactoring] 2. 중복 코드
  • [오브젝트 - 기초편] 변경과 설계
  • [오브젝트 - 기초편] 책임 할당하기
mxruhxn
mxruhxn
소소하게 개발 공부 기록하기
    반응형
    250x250
  • mxruhxn
    maruhxn
    mxruhxn
  • 전체
    오늘
    어제
    • 분류 전체보기 (150)
      • Java (21)
      • Spring (4)
      • Database (13)
      • Operating Syste.. (1)
      • Computer Archit.. (0)
      • Network (24)
      • Data Structure (6)
      • Algorithm (11)
      • Data Infra (7)
      • DevOps (12)
      • ETC (27)
      • Project (21)
      • Book (1)
      • Look Back (1)
  • 블로그 메뉴

    • 링크

      • Github
    • 공지사항

    • 인기 글

    • 태그

    • 최근 댓글

    • 최근 글

    • hELLO· Designed By정상우.v4.10.0
    mxruhxn
    [Refactoring] 1. 이해하기 힘든 이름
    상단으로

    티스토리툴바