포스트

[우아한 테크코스 프리코스] 프리코스 공통 피드백, 어떤 의미인지 알아보기

이번에 우아한 테크코스 프리코스 4주 과정(10.15 ~ 11.12) 에 참가했다. 아무래도 참가한 인원이 정말 많고, 특히 백엔드의 경우 1000명이 넘는 인원이 참가하는지라 주차별 미션 하나하나에 개인적 피드백을 하기 보다는 공통 피드백이 주어졌다.

전공자거나 미리 클린코드 혹은 객체지향 코드를 알고있다면 익숙한 내용들이 다수 있을 테지만, 나처럼 비전공자에 코딩 경력이 얼마 되지 않는 사람들에겐 약간 의아할 수 있는 내용들도 있다. 공통 피드백을 공부하면서 주목할만한 점, 느낀점 등을 정리해봤다.

1주차 피드백

1.이름을 통해 의도를 드러내라.

2.축약하지 않는다.

이 두 개의 피드백은 같은 의도를 공유한다고 생각한다. 즉, 오로지 코드를 통해 내 의도를 전달해라.

기능 사항을 구현하다보면 그것도 바빠서 메서드나 변수 이름 짓기 귀찮아지는데 축약하지도 말고 심지어 의도까지 드러내라고? 이유가 뭘까?

1
2
3
4
// 사각형의 넓이를 계산하는 메서드입니다.
public int calSpace(int a, int b) {
	return a * b
}

예를 들어 사각형의 넓이를 계산하는 메서드가 있다고 해 보자.

이 메서드가 다른 곳에서 쓰이고, 이 코드를 다른 사람이 읽는다면 이런 생각을 할 것이다.

  1. cal 이 뭐지?
  2. cal은 동사 같은데 space를 어떻게 한다는거지?
  3. 아니, 애초에 space가 정확하게 뭘 의미하는거야?

물론 cal의 경우 calculate 에서 빈번히 축약하는 경우가 많으므로 쉽게 유추 가능하지만, 지레짐작으로 넘겨짚는 것도 위험하다.

그렇기 때문에 위의 1~3 과정에 쓰일 리소스를 줄여, 그 시간에 더 생산적인 활동을 하는 것이 유용할 것이다.

1
2
3
public int calculateSquareSpace(int a, int b) {
	return a * b
}

조금 장황하더라도 의미 전달이 확실하게 되게 작명하는 것이 좋다.

3.의미 없는 주석을 달지 않는다.

주석의 경우는 굉장히 논쟁거리다.

“주석” 그 자체가 문제인 것이 아니라, 사람의 게으름이 문제다. 작동되는 코드라면 코드를 읽는 것으로 의도를 파악할 수 있지만, 주석은 수정하는 것을 깜빡하거나, 귀찮다고 수정하지 않는 경우도 생기기 마련이다. 즉, 주석은 거짓말을 할 가능성이 있다.

그렇기 때문에 꼭 필요한 주석만 쓰거나, 모호한 표현에 주석을 다는 것이 좋은 것 같다.

출처: https://code-yeongyu.tistory.com/50

2주차 피드백

1. 변수 이름에 자료형을 사용하지 않는다.

변수 이름에 자료형을 사용한다면, 추후 자료형을 변경해야 할 시, 관련된 모든 변수명을 변경해야 하기 때문에 번거로워진다!

1
2
3
4
5
List<Car> CarList = ...
// 나중에 Set으로 바꾸려면 변수명을 어떻게 바꿔야하지...?

List<Car> Cars = ...
// 추후에 어떤 자료형이 오든, 자동차들의 집합이겠구나!

2. 값을 하드 코딩하지 않는다.

값을 상수화 하는 데는 2가지 이점이 있다.

  1. 의미 파악

    2주차 미션의 핵심 기능이었던 4 이상이면 전진의 예시다.

    1
    2
    3
    4
    5
    
     public void move(int number) {
     	if (number >= 4) { // 여기서 4가 뭔데 가고 말고를 결정하는거지...?
     			go(...);
     		}
     }
    

    이는 다음과 같이 바꿀 수 있다.

    1
    2
    3
    4
    5
    6
    7
    
     private static final int MOVE_THRESHOLD = 4;
        
     public void move(int number) {
     	if (number >= MOVE_THRESHOLD) { // number 가 경계값 이상이어야 움직이는구나!
     			go(...);
     		}
     }
    

    비교적 용이하게 의미 파악이 가능해진다.

  2. 유지보수 용이성

    상수화 해둔 값은, 유지보수에서도 이점이 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     /* 월 원금을 구하는 메서드 */
     public static double calculateMonthlyPrincipal(int principal) {
         return principal / 12;
     }
        
     /* 월 이자를 구하는 메서드 */
     public static double calculateMonthlyInterest(int principal) {
         return principal * 0.1 / 12;
     }
    

    이때 할부를 10개월로 바꾼다거나, 이율을 바꾸고 싶다면, 관련된 모든 숫자를 찾아서 하나하나 바꿔야 한다. 매우 번거롭다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
     private static final int INSTALLMENT_MONTHS = 12;
     private static final double INTEREST_RATE = 0.1;
        
     /* 월 원금을 구하는 메서드 */
     public double calculateMonthlyPrincipal() {
         return this.principal / INSTALLMENT_MONTHS;
     }
        
     /* 월 이자를 구하는 메서드 */
     public double calculateMonthlyInterest() {
         return this.principal * INTEREST_RATE / INSTALLMENT_MONTHS;
     }
    

    이렇게 바꾼다면, 최상단의 상수값만 변경해 쉽게 수정할 수 있다.

출처: https://tecoble.techcourse.co.kr/post/2020-05-07-avoid-hard-coding/

3. 처음부터 큰 단위의 테스트를 만들지 않는다.

이미 다 만들어진 기능들의 경우, 어디가 잘못됐는지 파악하기 어렵다.

1
2
3
4
5
6
7
8
9
10
11
12
public class User {

	public void all() { // 왜 안돼?
		A
		B
		C
	}
	
	public void A(...) // 나중에 테스트 해야지~
	public void B(...) // 나중에 테스트 해야지~
	public void C(...) // 나중에 테스트 해야지~
}

추후에 이 all() 메서드를 테스트하기 어렵다. A, B, C 중 어디가 잘못됐는지 짐작하기 어렵기 때문이다. 그렇기 때문에 각각의 메서드는 한 가지 기능만 하게 하고, 테스트하는것이 추후에 에러를 쉽게 잡을 수 있다. 메서드가 한 가지 일만 하게 하라 는 피드백과도 상통한다.

1
2
3
4
5
6
7
8
9
10
11
12
public class User {

	public void all() { // 기능 보장!
		A
		B
		C
	}
	
	public void A(...) // 만든 직후 테스트
	public void B(...) // 만든 직후 테스트
	public void C(...) // 만든 직후 테스트
}

3주차 피드백

1. 연관성이 있는 상수는 static final 대신 enum을 사용한다.

지금까지 상수는 static final 을 통해 사용해왔다. 근데, enum은 왜 사용해야 할까?

enum은 enumeration 의 약자로, 열거 라는 뜻을 가지고 있다. 즉 비슷한 것들끼리 나열해놓으라는 소리다. 사용해보고 느낀 장점들은 다음과 같다.

  1. 기본적으로 public static final 형태로 생성되기에 보일러 플레이트 코드를 줄일 수 있다.
  2. 하나의 상수에 여러가지 상태를 저장할 수 있다.

    1
    2
    3
    4
    5
    6
    7
    8
    
     public enum Rank {
         FIRST(6, 2_000_000_000),
         SECOND(5, 30_000_000),
         THIRD(5, 1_500_000),
         FOURTH(4, 50_000),
         FIFTH(3, 5_000),
         MISS(0, 0);
     ...
    

    로또 상금의 매칭 갯수, 수상 금액을 정리해둔 enum이다. 단순히 상수라고 해서 한 가지 상태만 갖고있게 하는 것이 아닌, 여러가지 상태를 갖게 할 수 있어서 매우 편리했다.

  3. 리팩토링 시, 변경 범위가 최소화된다.

    만약 새로운 상금이 추가된다면? 이곳저곳 돌아다니면서 추가할 필요 없이, Rank enum 한 곳에서만 추가하면 된다.

    (출처: https://techblog.woowahan.com/2527/)

2. 필드 변수를 줄이기 위해 노력한다.

객체를 설계할때, 그 객체가 어떤 필드 변수를 갖게 할지는 정말 중요한 포인트다. 중요한 만큼 무게감을 느끼면서 배정해야 한다. 필드 변수가 많다는 것은, 해당 객체가 너무 많은 일을 하고 있을 가능성이 있다. 그 만큼 버그 가능성도 늘어나고, 재사용성도 줄어든다.

1
2
3
4
5
6
7
8
9
public Class Promotion {
	private final String name;
	private final int get;
	private final int buy;
	private final LocalDate startDate;
	private final LocalDate endDate;
	
	...
}

4주차 미션에서 사용된 Promotion 클래스다. 현재 이 객체는 너무 많은 상태를 관리해야한다. 프로모션의 날짜도 관리하고, 프로모션의 정책도 관리한다.

이때 내가 느낀 가장 간단하게 필드 변수를 줄일 수 있는 방법은 새 객체를 만들어, 그곳에서 관리하는 방법이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public Class Promotion {
	private final String name;
	private final PromotionPolicy promotionPolicy
	
	...
}

public Class PromotionPolicy {
	private final int get;
	private final int buy;
	private final Date date;
	...
}

public Class Date {
	private final LocalDate startDate;
	private final LocalDate endDate;
	...
}

이렇게 나눈다면 프로모션 정책에 대한 로직은 Policy 객체 내에서, 날짜에 대한 로직은 Date 객체 내에서 처리 가능하다.



이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.