Skip to content

Commit

Permalink
[Item68]: 일반적으로 통용되는 명명 규칙을 따르라 (#157)(세미) (#174)
Browse files Browse the repository at this point in the history
* [Item68]: 일반적으로 통용되는 명명 규칙을 따르라 (#157)(세미)

* [Item73]: 추상화_수준에_맞는_예외를_던지라.md
  • Loading branch information
semi-cloud authored Sep 10, 2023
1 parent 90930a5 commit b83d9d5
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
## 🌱 철자 규칙
### ☁️ 패키지와 모듈 이름
각 요소를 `.` 으로 구분하여 **계층적**으로 짓는다.
만약 조직 바깥에서도 사용될 패키지라면, 조직의 인터넷 도메인 이름을 역순으로 사용하면 된다. ex) `com.google`

각 패키지 이름은 소문자를 사용한 8자 이하의 짧은 단어 혹은 **약어**를 추천한다.
`utilities` 보다는 `util` 이 좋다.

### ☁️ 클래스와 인터페이스 이름
하나 이상의 단어로 이루어지며, 각 단어는 대문자로 시작해야 한다
단어의 첫 글자만 딴 약자나 `max`, `min` 처럼 널리 통용되는 줄임말을 제외하고 단어를 줄여 쓰면 안된다.

### ☁️ 메서드와 필드 이름
첫 글자를 소문자로 쓴다는 점만 빼면 클래스 명명 규칙과 같다. 만약 첫 단어가 약자라면, 단어 전체가 소문자여야 한다.

#### 🔖 상수 필드
단, 상수 필드는 예외적으로 모두 **대문자**로 쓰며 단어 사이는 밑줄로 구분한다.
```java
private static final int NEGATIVE_INFINITY = XX
```
주의할 점은 `static final` 필드이면서, 가리키는 객체가 불변이라면 비록 그 타입은 가변이더라도 상수 필드라는 것이다. 즉, `static final` 타입이 **기본 타입이나 불변 참조 타입**이라면 상수 필드에 해당한다.

### ☁️ 타입 매개변수
타입 매개변수의 이름은 보통 한 문자로 포함한다.
>
`T` : 임의의 타입
`E` : 컬렉션 원소의 타입
`K`, `V`: 맵의 키와 값
`X` : 예외
`R` : 메서드 반환 타입
`T`, `U`, `V` (`T1`, `T2`, `T3`) : 임의 타입의 시퀀스

## 🌱 문법 규칙
### ☁️ 클래스

보통 **단수 명사나 명사구**를 사용한다.

1. 객체를 생성할 수 없는 클래스의 이름은 보통 복수형 명사로 짓는다.(ex) `Collectors` )
2. 인터페이스 이름은 클래스와 똑같거나 `able` 혹은 `ible` 로 끝나는 형용사로 짓는다. (ex) `Runnable`, `Accessible`)
3. 애너테이션은 명사, 동사, 전치사, 형용사가 두루 쓰인다. (ex) `Inject`, `ImplementedBy`)

### ☁️ 메서드
어떤 동작을 수행하는 메서드 이름은 **동사나 동사구**로 짓는다. 단, 동사는 **현재형**이여야 한다. (ex) `drawImage` )

+ `is`, `has` : `boolean` 값을 반환하는 메서드 (ex) `isDigit`, `hasSiblings`)

+ `명사`, `get` : 해당 인스턴스의 속성을 반환하면서 반환 타입이 `boolean` 이 아닌경우 (ex) `size`, `getTime` )
```java
if (car.speed() > 2 * SPEED_LIMIT)
generateAudibleAlert("경찰 조심하세요!");
```

+ `toType` : 객체의 타입을 바꿔서 다른 타입의 다른 객체를 반환하는 인스턴스 메서드 (ex) `toString`, `toArray` )

+ `asType` : 객체의 내용을 다른 뷰로 보여주는 메서드 (ex) `asList` )

+ `typeValue` : 객체의 값을 기본 타입 값으로 반환하는 메서드 (ex) `intValue` )

>🔖 **정적 팩터리 이름**
from, of, valueOf, instance, getInstance, newInstance, getType, newType을 흔히 사용


### ☁️ 필드 이름
필드 이름에 관한 문법 규칙은 클래스, 인터페이스, 메서드 이름에 비해 덜 명확하고 덜 중요하다. API 설계를 잘 했다면 필드가 직접 노출될 일이 거의 없기 때문이다.

+ `boolean` 타입 : boolean 접근자 메서드에서 앞 단어를 뺀 형태
+ 이외의 타입 : 명사 / 명사구 사용
72 changes: 72 additions & 0 deletions Ch10/item73/추상화_수준에_맞는_예외를_던지라.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
메서드가 **저수준 예외를 처리하지 않고 바깥으로 전파**( `throws` )해버릴 때, 수행하려는 일과 관련 없어 보이는 예외가 튀어나온다. 이는 내부 구현 방식을 드러내어 윗 레벨의 API를 오염시킬 수 있으므로 위험하다.

#### Spring
대표적인 예시로, 스프링에서도 데이터 계층에서 특정 DB에 종속되는 `SQLException` 과 같은 저수준 예외를, 예외 변환기 ( `PersistenceExceptionTranslator`) 를 통해 고수준 `DataAccessException` 으로 변환시킨다.

### ☁️ 예외 번역(Exception Translation)
이 문제를 피하려면, **상위 계층에서는 저수준 예외를 잡아 자신의 추상화 수준에 맞는 예외로 바꾸어 던져야** 한다. 그리고 이를 **예외 번역**이라 한다.

```java
try {
...
} catch (LowerLevelException e) {
throw new HigherLevelException(...);
}
```

예외 번역을 사용한 예로 `AbstractSequentialList` 를 들어보자.

#### AbstractSequentialList

```java
/**
이 리스트 안의 지정한 위치의 원소를 반환한다.
@throws IndexOutOfBoundsException index가 범위 밖이라면,
즉 {@code index < 0 || index >= size()}이면 발생한다.
**/
public E get(int idex) {
ListIterator<E> i = listIterator(index);
try {
return i.next();
} catch (NoSuchElementException e) {
throw new IndexOutOfBoundsException("인덱스: " + index);
}
}
```

### ☁️ 예외 연쇄(Exception Chaining)

예외 연쇄란, 문제의 근본 원인인 저수준 예외를 고수준 예외에 실어 보내는 방식이다. 따라서 예외를 번역할 때, 저수준 예외가 디버깅에 도움이 된다면 예외 연쇄를 사용하도록 하자.

```java
try {
...
} catch (LowerLevelException cause) {
// 저수준 예외를 고수준 예외에 실어 보낸다.
throw new HigherLevelException(cause);
}

```

대부분의 표준 예외는 아래와 같이 예외 연쇄용 생성자를 갖추고 있다.
```java
class HigherLevelException extends Exception {
HigherLevelException(Throwable cause) {
super(cause);
}
}
```
문제의 원인을 `getCause` 메서드로 프로그램에서 접근할 수 있게 해주어, 원인과 고수준 예외의 스택 추적 정보를 잘 통합해준다.

### ☁️ 주의 사항
결론적으로 예외를 전파( `throws` )하는 것보다 예외 번역이 더 나은 방법이지만, 남용해서는 안된다. 우선순위는 다음과 같다.

1. 가능하다면 저수준 메서드가 반드시 성공해 예외를 발생시키지 않도록 한다.
2. 상위 계층 메서드의 매개변수 값을 아래로 넘기기 전에 미리 검사한다.
3. 예외를 예방 및 처리 불가능할때 예외 번역을 사용한다.

만약 아래 계층에서의 예외가 불가피하다면, 상위 계층에서 예외를 조용이 처리하여 API 호출자에게까지 전파하지 않는 방법도 존재한다. 이 경우, 발생한 예외는 `java.util.logging` 같은 로깅 기능을 활용하여 기록해두자.


> 📚 **핵심 정리**<br>
아래 계층의 예외를 예방하거나 스스로 처리할 수 없고, 상위 계층에 그대로 노출하기 곤란하다면 예외 번역을 사용하자. 이때 예외 연쇄를 이용하면 상위 계층에는 맥락에 어울리는 고수준 예외를 던지면서, 근본 원인도 함께 알려주어 오류를 분석하기에 좋다.

0 comments on commit b83d9d5

Please sign in to comment.