7장 - 컴파일러와의 협업
7.1 컴파일러에 대해 알아보기
- 정지문제 (halting problem)
- 런타임 동안 어떤 일이 일어날지 정확히 말할 수 없는 이유
- 보수적 분석 (conservative analysis)
- 프로그램이 안전하다고 보장할 수 없는 경우 컴파일러는 프로그램을 허용하지 않음
- 프로그램에 특정한 실패 가능성이 없다는 것을 보증
- 장점1) 메서드가 모든 경우에서 return 하는지 확인
- 장점2) 확정 할당으로 초기화되지 않은 변수에 대한 접근 막음
- 장점3) 접근 제어로 데이터 캡슐화 지원
class Class { private sensitiveMethod() { } } let c = new Class(); c.sensitiveMethod(); // 컴파일러 오류 발생
- 장점4) 타입(형) 검사기는 속성을 보증함
- 약점1) null 참조 <- strict null 검사 웬만하면 해제하지 말 것
- 약점2) 산술오류
- 약점3) out of bounds 오류
- 약점4) 무한루프 체크 못하니까 while대신 for나 forEach 사용하기
- 약점5) 교착상태, 경쟁상태, 기아상태
7.2 컴파일러 사용
- 컴파일러 활용
- 무언가 수정할 때 TODO 리스트로 사용하는 것 -> 컴파일러가 오류 뱉는거 활용
- 순서 강제화를 이용한 안전성 확보 -> p.201 참고
- 캡슐화 강제를 통한 안전성 확보 -> 컴파일러의 접근 제어를 사용해서 불변속성 지역화
- 컴파일러로 사용하지 않는 코드 감지
- 확정 값을 통한 안전성 확보
interface NonEmptyList<T> { head: T; } class Last<T> implements NonEmptyList<T> { constructor(public readonly head: T) {} } class Cons<T> implements NonEmptyList<T> { constructor( public readonly head: T, public readonly tail: NonEmptyList<T>) {} }
- 확정 값을 통한 안전성 확보
- 컴파일러 잘못 쓰는 방법 3가지
- 타입 잘못 사용하기
- 형 변환
- any 사용
- 컴파일 시간에서 런타임으로 판단에 필요한 정보 옮기기
- 게으름
- 기본값 사용하지 말기
- 인터페이스에서만 상속받기
- 처리를 강제한 에외 -> try, catch 사용해서 명시적으로 사용하기
- 아키텍처에 대한 이해 부족
- 타입 잘못 사용하기
7.3 컴파일러 신뢰하기
📌 정상적인 경고의 개수는 0이어야 한다!!! -> 매달 조금씩 줄여보기
7.4 컴파일러만 신뢰할 것
컴파일러는 코드가 우리가 예상하는 문제를 해결할지 여부는 알 수 없지만, 우리가 생각하지 못한 이유로 프로그램이 손상될 수 있는지 여부는 알려줄 수 있음.