[Clean-Code] Chapter. 17(G24~)~부록:동시성
Clean-Code_week7_yerimi11 (p.286~)
G23: If/Else 혹은 Switch/Case 문보다 다형성을 사용하라
- ‘switch 문 하나’ 규칙을 따른다. 즉, 선택 유형 하나에는 switch 문을 한 번만 사용한다.
G24: 표준 표기법을 따르라
- 팀이 정한 표준은 팀원들 모두가 따라야 한다.
- 모두가 동의한 위치에 넣는다는 사실이 중요하다.
G26: 정확하라
- 잠금과 트랜잭션 관리를 건너뛰는 행동은 아무리 잘봐줘도 게으름이다.
G28: 조건을 캡슐화하라
- 가능하면 긍정 조건으로 표현하라
G30: 함수는 한 가지만 해야 한다
- 한 가지만 수행하는 좀 더 작은 함수 여렷으로 나눠야 마땅하다.
G33: 경계 조건을 캡슐화하라
코드 여기저기에 +1이나 -1을 흩어놓지 않는다.
경계조건은 변수로 캡슐화
if(level + 1 < tags. length) -> int nextLevel level + 1; if(nextLevel < tags. length)
G34: 함수는 추상화 수준을 한 단계만 내려가야 한다
- 함수 내 모든 문장은 추상화 수준이 통일해야한다. 그리고 그 추상화 수준은 함수 이름이 의미하는 작업보다 한 단계만 낮아야 한다.
G36: 추이적 탐색을 피하라
- 디미터의 법칙(Law of Demeter)
- ‘부끄럼 타는 코드 작성 Write Shy Code’라고도 한다.
- 자신이 직접 사용하는 모듈만 알아야 한다는 뜻
J2: 상수는 상속하지 않는다
N3: 가능하다면 표준 명명법을 사용하라
T2: 테스트는 커버리지 도구를 사용하라
- 커버리지 도구는 테스트가 빠뜨리는 공백을 알려준다.
T3: 사소한 테스트를 건너뛰지 마라
T7: 실패 패턴을 살펴라
- 합리적인 순서로 정렬된 꼼꼼한 테스트케이스는 실패 패턴을 드러낸다.
[동시성]
스레드를 차단하지 않는(nonblocking) 방법
최신 프로세서는 차단하지 않고도 안정적으로 값을 갱신한다. 자바 5VM은 이를 이용한다.
예를 들어,다음 클래스는 다중 스레드 환경에서 값을 안전하게 갱신하기 위해 동기화를 수행한다. 즉,스레드를 차단한다.
public class ObjectWithValue { private int value; public void synchronized incrementValue() { ++value; } public int getValue() { return value; } }
CAS(Compare and Swap)
- synchronized 키워드는 언제나 락lock을 건다. 둘째 스레드가 같은 값을 갱신하지 않더라도 무조건 락부터 건다.
일화
하루에 한 번 정도 터미널 하나가 ‘먹통이 되었다’.
-> 링 버퍼 카운터와 링 버퍼 포인터가 일치하지 않아 생기는 현상이라는 사실을 발견했다.
문제의 링 버퍼가 터미널 출력을 제어했기 때문이다. 포인터는 버퍼가 비었다고 말하는데 카운터는 버퍼가 꽉 찼다고 말했다.
버퍼가 비었으므로 화면에 표시할 내용이 없었고, 버퍼가 꽉 찼으므로 누구도 버퍼에 추가하지 못했다.서버-기반 잠금 (일반적으로 바람직)
- 코드 중복이 줄어든다.
- 성능이 좋아진다. 단일스레드 환경으로 시스렘을 배치할 경우 (다중 스레드 서버를 단일스레드 서버로) 서버만 교체하면 오버헤드가 줄어든다.
- 오류가 발생할 가능성이 줄어든다.
- 스레드 정책이 하나다.
- 공유 변수 범위가 줄어든다.
서버 코드에 손대지 못한다면?
- ADAPTER 패턴을 사용해 API를 변경한 후 잠금을 추가한다.
디버깅 문을 추가하면 코드가 바뀌어 데드락은 다른 상황에서 발생한다.
- 예를 들어,누군가 디버깅문을 추가한 후 문제가 ‘사라진다’. 디버깅 코드가 문제를 '해결'하므로 문제는 그대로 시스템에 남게된다.