- Code Complete
- 고품질 코드 작성
- Class
-
추상 데이터형(abstract data type; ADT), 132p
클래스와의 차이
- 추상 데이터형에 상속과 다형성을 더한 것이 클래스
장점
- 구현 세부 사항을 감출 수 있다.
- 변경이 전체에 영향을 미치지 않는다.
- 인터페이스가 더 많은 정보를 제공하도록 만들 수 있다.
- 성능을 향상시키기 쉽다.
- 프로그램이 명백하게 정확해진다.
- 프로그램의 가독성이 높아진다.
- 전체 프로그램에 데이터를 넘길 필요가 없다.
- 저수준 구현 구조체 대신 현실 세계의 개체를 다룰 수 있다.
사용 시 원칙
- 전형적인 저수준 데이터형을 저수준 데이터형이 아닌 ADT로 만들거나 사용하라.
- 파일과 같은 일반적인 객체를 ADT로 취급하라.
- 간단한 객체도 ADT로 취급하라.
- ADT가 저장된 매체와 독립적으로 ADT를 참조하라.
-
좋은 클래스 인터페이스, 140p
좋은 추상화
- 클래스 인터페이스가 일관된 추상화 수준을 갖도록 한다.
- 클래스가 구현하고 있는 추상화가 무엇인지 이해해야 한다.
- 서로 반대되는 기능을 갖는 서비스 쌍을 제공하라.
- 관련이 없는 정보를 다른 클래스로 옮겨라.
-
가능하면 인터페이스를 의미론적이기보단는 프로그래밍적으로 만들어라.
의미론적: 주석으로 설명 프로그래밍적: Assert 등 프로그래밍적인 인터페이스 요소로 강제화
- 코드 변경 시 인터페이스의 추상화가 망가지지 않도록 주의한다.
- 인터페이스 추상화에 맞지 않는 공개 멤버를 추가하지 말라.
- 추상화와 응집도를 함께 고려하라.
좋은 캡슐화
- 캡슐화는 추상화보다 더 강력한 개념.
- 클래스와 멤버의 접근성을 최소화하라.
- 멤버 데이터를 public으로 노출하지 말라.
- 클래스 구현 세부 사항을 클래스의 인터페이스에 입력하지 말라.
- 클래스의 사용자를 가정하지 말라.
- 프렌드 클래스를 피하라(?).
- 어떤 루틴이 공개 루틴만 사용한다고 해서 public 인터페이스에 두지 말라.
- 코드를 작성할 때의 편의성보다 가독성이 높은 코드를 작성하라.
-
캡슐화의 의미론적인 위반을 각별히 주의하라.
클래스 A의 PerformFierstOperation() 루틴이 InitializeOperations() 루틴을 자동으로 호출하는 것을 알고 있기 때문에 클래스 A의 InitializeOperations() 루틴을 호출하지 않는다.
위 예시의 문제는 클라이언트의 코드가 private 구현에 의존하고 있다는 점이다. 따라서 인터페이스 문서만으로 클래스를 어떻게 사용해야 하는지 알 수 없다. 결국 클래스가 어떻게 구현되어 있는지 확인해야 하는 상황이 발생한다.
- 지나치게 밀접한 결합을 주의하라.
-
설계와 구현 문제, 152p
포함(has a) 관계
- 포함을 통해서 ‘has a’를 구현하라.
- 최후의 수단으로 비공개 상속을 통해서 ‘has a’를 구현하라.
- 약 7개 이상의 데이터 멤버를 포함하는 클래스를 주의하라.
상속(is a) 관계
- 공개 상속을 통해 ‘is a’를 구현하라.
- 상속을 고려해서 설계하고 문서화하라. 그게 아니라면 상속을 금지하라.
- 리스코프 치환 원칙(LSP)을 따르라.
- 상속받고 싶을 때만 상속받게 하라.
- 오버라이트가 불가능한 멤버 함수를 ‘오버라이드’하지 말라.
- 공통으로 사용되는 인터페이스와 데이터, 해우이를 상속 단계에서 가능한 한 가장 높은 곳으로 옮겨라.
- 인스턴스가 하나뿐인 클래스를 의심하라.
- 파생 클래스가 하나뿐인 기본 클래스를 의심하라.
- 루틴을 오버라이드했는데 파생된 루틴 내부에서는 아무것도 하지 않는 클래스들을 의심하라.
- 깊은 상속 구조를 피하라.
- 광범위한 타입 검사보다 다형성을 택하라.
- 모든 데이터를 보호가 아닌 비공개로 만들어라.
멤버 함수와 데이터
- 클래스에 가능한 한 적은 수의 루틴을 유지하라.
- 원하지 않는 멤버 함수와 연산자가 암묵적으로 생성되지 않도록 하라.
- 클래스에서 호출되는 루틴의 수를 최소화하라.
- 다른 클래스에 대한 간접적인 루틴 호출을 최소화하라.
- 일반적으로 클래스가 다른 클래스와 협력하는 정도를 최소화하라.
생성자
- 가능하다면 모든 멤버 데이터를 모든 생성자에서 초기화하라.
- 비공개 생성자를 사용해 싱글턴 속성을 구현하라.
- 다른 사실이 증명될 때까지 얕은 복사보다 싶은 복사를 택하라.
-
클래스를 작성하는 이유, 162p
- 현실 세계의 객체를 모델링한다.
- 추상 객체를 모델링한다.
- 복잡성을 줄인다.
- 복잡성을 고립시킨다.
- 구현 세부 사항을 숨긴다.
- 변경의 효과를 제한한다.
- 전역 데이터를 숨긴다.
- 매개변수 전달을 간소화한다.
- 중앙 집중 관리한다.
- 코드 재사용을 돕는다.
- 프로그램 전체를 고려한다.
- 연관된 기능을 패키지로 구성한다.
- 특정한 리팩터링을 수행한다.
- God 클래스를 생성하지 말라.
- 관련이 없는 클래스를 제거하라.
- 동사를 뒤에 붙는 클래스를 피하라.
-
- Class
- Variable
- 변수 사용 시 고려해야 할 사항, 255p
- 변수 초기화 가이드라인, 255p
- 변수를 선언할 때 초기화한다.
- 변수가 처음 사용되는 곳 근처에서 초기화한다.
- 이상적으로 각 변수가 처음 사용되는 곳 가까이에서 변수를 초기화하고 정의한다.
- 가능하다면 final이나 const를 사용한다.
- 카운터와 누산기(i, j, sum, total 등 변수)를 재사용할 때는 초기화 해야 한다.
- 클래스의 멤버 데이터를 생성자에서 초기화한다.
- 다시 초기화해야 할 필요가 있는지 검사한다.
- 이름 상수를 한 번 초기화하고 실행 코드로 변수를 초기화한다.
- 모든 변수를 자동으로 초기화하는 컴파일러 설정을 사용한다.
- 컴파일러의 경고 메시지를 활용한다.
- 입력 매개변수의 유효성을 검사한다.
- 메모리 접근 도구를 사용해 부적절한 포인터를 검사한다.
- 프로그램을 시작할 때 메모리를 초기화한다.
-
범위, 259p
변수에 대한 참조를 지역화하라.
변수의 수명을 가능한 한 짧게 유지한다.
범위를 최소화하기 위한 일반적인 가이드라인
- 루프에서 사용되는 변수는 루프를 포함하고 있는 루틴의 시작이 아니라 루프 바로 앞에서 초기화한다.
- 변수를 사용하기 바로 전까지 변수에 값을 할당하지 않는다.
- 연관된 명령문을 그룹화한다.
- 연관된 명령문 그룹을 별도의 루틴으로 나눈다.
- 처음에는 범위를 최대한 제한하고 필요한 경우에만 변수의 범위를 늘린다.
- 지속성, 267p
- 데이터가 예상한 것보다 오래 존재하는 경우 문제가 될 수 있음
- 변수를 사용하기 전에 초기화하고, 사용 후에는 반환하는 습관을 들여라.
- 가능한 한 그 범위는 짧게 유지하는 것이 좋다.
-
결합 시점, 268p
변수와 값이 결합되는 시점은 아래와 같고, 결합 시점이 이를 수록 유연성이 낮아지지만 복잡성이 줄어듬. 적절한 선택 필요.
- 코드 작성 시간(매직 넘버 사용)
- 컴파일 시간(이름 상수 사용)
- 로드 시간(윈도우 레지스트리 파일이나 자바 속성 파일과 같은 외부의 소스로부터 값을 읽어 들임)
- 객체 생성 시간(윈도우가 생성될 때마다 값을 읽어 들임)
- 적시에(윈도우가 그려질 때마다 값을 읽어 들임)
- 변수를 한 가지 목적으로만 사용하기, 271p
- 각 변수를 한 가지 목적만을 위해서 사용하라.
-
숨은 의미가 있는 변수를 피하라
pageCount 변수에 있는 값이 출력된 페이지 수를 나타낼 때, -1은 오류가 발생했다는 것을 의미 → WRONG
customerId 변수가 고객 번호를 나타낼 때, 500,000보다 크면 연체된 계정의 수를 구하기 위해서 500,000을 뺀다. → WRONG
bytesWritten 변수가 출력 파일에 기록된 바이트 수를 나타낼 때, 이 값이 음수이면 출력 파일에 사용된 디스크의 수를 가리킨다. → WRONG
- 선언된 모든 변수를 사용하는지 확인하라.
- 변수 초기화 가이드라인, 255p
- 변수 이름의 기능, 275p
-
좋은 이름을 짓기 위한 고려 사항
최적의 이름 길이
- 10~16, 9~15 사이의 길이가 적당
-
금발 소녀와 세 마리 곰 스타일로 짓는 게 도움 될 것이다.
numberOfPeopleOnTheUsOlympicTeam: Too long
not: Too short
numTeamMembers: good
범위가 변수명에 미치는 효과
- 전역 네임스페이스에 있는 변수에는 한정자를 사용하라.
변수 이름의 계산값 한정자
- Total, Sum 등과 같은 한정자로 변수의 이름을 만들 경우 이름 끝에 한정자 붙여라. ex) revenueTotal, expenseTotal
- 단, num은 맨 앞에 붙일것. ex) numCostomers
일반적인 변수명의 반의어
- 반의어를 정확하게 사용할것.
- source/target
- source/destination
- next/previous
- visible/invisible
-
특정 타입의 데이터 이름 짓기
반복문 인덱스 이름
-
관습적으로 i, j, k 사용
예외. 의미 있는 변수명을 사용해야할 때
- 반복문 외부에서 사용해야 한다면 recordCount와 같이 의미 있는 이름으로 사용할것.
- 반복문이 길어질 때
- 반복문이 중첩될 때
상태 변수 이름
- 의미가 애매한 flag와 같은 변수 사용하지 말 것.
임시 변수 이름
- 임시 변수를 조심하라
불린 변수 이름
- 전형적인 불린 변수의 이름을 기억한다.
- done
- error
- found
- success / ok
- 참이나 거짓의 의미를 함축하는 불린 변수의 이름을 사용한다.
- status X / statusOK O
- sourceFile X / sourceFileAvailable
- 긍정적인 불린 변수 이름을 사용한다.
- notFound X / found O
열거형의 이름
- Color_, Month_와 같은 접두사를 활용하면 구분이 쉽다.
상수 이름
-
상수 이름은 상수가 가르키는 숫자보다는 상수가 표현하는 대상이 더 추상적이어야 한다.
ex. FIVE X / CYCLES_NEEDED O
-
-
읽기 쉬운 짧은 이름
일반적인 축약어 가이드라인
- 표준 축약어 사용(사전)
- 불필요한 모음 제거(computer → cmptr, integer → intgr)
- 관사와 접속사 제거(and, or, the 등)
- 각 단어의 첫 번째 문자나 처음 문자 몇 개를 사용
- 첫 번째나 두 번째, 세 번째에서 일관성 있게 단어를 자른다
- 각 단어의 첫 번째와 마지막 문자를 유지
- 이름에서 가장 중요한 단어를 최대 세 단어까지 사용
- 불필요한 접미사 제거(ing, ed 등)
- 각 음절에서 가장 뚜렷한 소리를 유지
- 변수의 의미를 변경하지 않도록
- 글자 수가 적절히 줄어들 때까지 이 과정 반복
음성 축약
- skating → ska8ing, highlight → hilite
축약어에 대한 의견
- 단어에서 한 문자를 없애는 방법으로 축약하지 않는다.
- 일관성 있게 축약한다.
- 발음할 수 있는 이름을 만든다.
- 잘못된 발음을 유발할 수 있는 조합을 피한다.
- 이름 충돌을 해결하기 위해서 유의어 사전을 사용한다.
- 매우 짧은 이름은 코드 내 변환 테이블을 사용하여 문서화한다.
- 모든 축약어를 프로젝트 수준의 ‘표준 축약어’ 문서에 기록한다.
- 이름은 코드를 작성하는 사람보다 읽는 사람에게 더 중요하다는 점을 기억한다.
-
피해야 할 변수 이름
- 오해의 소지가 있는 이름이나 축약어를 피한다.
-
유사한 의미가 있는 이름을 피한다.
ex. (recordNum / numRecord), (fileNumber / fileIndex)
-
이름은 유사하지만 의미가 다른 변수를 피한다.
ex. clientRecs vs clientRps X → clientRecords vs clientReports O
- 이름에 숫자를 넣는 것을 피한다.
- 이름에 철자가 틀린 단어가 없도록 한다.
- 영어에서 일반적으로 잘못 표기되는 단어를 피한다.
- 대소문자만으로 변수의 이름을 구분하지 않는다.
- 여러 가지 자연어를 사용하지 않는다.
- 표준 데이터형과 변수, 루틴의 이름은 사용하지 않는다.
- 변수가 표현하는 것과 전혀 관련이 없는 이름을 사용하지 않는다.
- 읽기 어려운 문자를 포함하는 이름을 피한다.
-
- 변수 사용 시 고려해야 할 사항, 255p
-
개발 프로세스
소프트웨어 정신에 대한 주제, 904p
- 최대한 간결하게 → 사람이 읽는 것임
- 경고를 무시하지 말자
-
문제를 해결하기 위해 세부 구현 사항은 숨겨야 한다.
최상위 수준의 코드에서 “i는 직원 파일에서 얻은 레코드의 인덱스를 나타내며 잠시 후에는 고객의 계정 파일의 인덱스를 나타내기 위해서 사용된다.” 와 같은 주석 덩어리를 포함하여서는 안 된다.
- 고품질 코드 작성