코드 작성 기초 (Basic Coding)
기본 데이터 형
일반적인 숫자의 사용시 유의할 점
- 매직넘버(Magic Number)를 피하라
- 0과 1은 그냥 사용
- 0으로 나누는 것은 미연에 방지
- 형 변환은 명확하게 수행
- 예) y = x + (float) i
- 서로 다른 형을 비교하지 않는다
- 컴파일러의 경고에 주의
정수(integer)를 사용할 때 주의할 점
- 정수 나눗셈 검사
- 정수 오버플로우 검사
- 중간 결과에서 오버플로우 검사
int termA = 1000000;
int termB = 1000000;
int product = termA * termB / 1000000;
System.out.println(...+product);
부동소수점 변수 사용시 주의할 점
- 서로 크기가 매우 다른 수를 더하거나 빼지 않는다
- 가장 작은 수부터 더하는 것이 좋다
- 동치 비교를 피한다
- 라운딩 오류를 예측한다
- 더 큰 정밀도를 사용
- BCD 표기법을 사용한 변수로 변경
- 정수형을 사용(화폐 등을 계산할 때)
- 특정한 데이터 형을 지원하는 언어 또는 라이브러리가 있는지 확인
문자와 문자열
- 매직문자와 매직문자열을 사용하지 않는다
- 하나 모자름(off-by-one) 오류 주의
- 사용하고 있는 언어가 유니코드(Unicode)를 어떻게 지원하는지 파악
- 국제화(Internationalization, i18n) / 지역화(Localization, L10n) 전략을 초기에 결정
- 만약 알파벳만을 사용할 것이면 ISO 8859를 사용하는 것이 좋다
- 다중 언어를 지우너하려면 유니코드를 사용
- 문자열 타입 간에 일관된 변환 전략 사용
- 프로그램이 다중 문자코드를 지원하는 경우, 내부적으로는 유니코드를 쓰고 I/O에만 코드 변환 사용
불린(Boolean) 변수
- 프로그램을 문서화하기 위해 불린 변수를 사용
- 필요하면 고유한 불린 타입을 만든다
- 불린 타입이 제공되지 않는 언어(C와 같은) 경우, 0 = False, 1 = True
if ( (elementIndex < 0) || (MAX_ELEMENTS < elementIndex) || (elementIndex == lastElementIndex) ) )
{
…
}
// ↓↓↓↓
finished = (elementIndex<0) || (MAX_ELEMENTS < elementIndex) ;
repeatedEntry = elementIndex == lastElementIndex;
if (finished || repeatedEntry) {
…
}
열거 형의 사용
- 가동성 향상
- 신뢰성
- 컴파일러가 정수 또는 상수를 사용할 때 보다 타입 검사를 강력하게 할 수 있다
- 수정을 용이하게 하기 위해
- 기존 요소의 할당 값 변경 또는 새로운 요소의 추가가 용이
- 불린 변수에 대한 대안
- 불린 변수는 2가지만 표시할 수 있지만 열거형은 Status_Success, Status_Warning, Status_FatalError 등과 같이 다양한 값을 표현하기에 유리
- 타당하지 않는 값 검사
- 반복문의 범위를 지정하기 위해 열거형의 처음과 마지막 엔트리를 정의
- 연속되지 않는 경우 주의
- 열거 형의 첫째를 타당하지 않는 값으로 남겨둔다
- 대다수의 언어가 열거형의 처음을 0로 할당하므로 초기화되지 않은 변수(0일 가능성이 높음)를 잡는데 유리
명명된 상수
- 리터럴 대신 명명된 상수를 사용
- 확실한 리터럴이더라도 명명된 상수를 쓰는 것이 좋다
for (int i=1; i<12; i++) {
profit[i] = revenue[i] –expense[i];
}
// ↓↓↓↓
for (int i=1; i<=NUM_MONTHS_IN_YEAR) …
// or
for (int i=Month_Jan ; i<=Month_Dec; i++) …
배열의 사용
- 배열의 모든 인덱스가 경계 내에 있는지를 확인
- 경계를 확인해 주는 언어(Java)가 있으나 그렇지 않은 것(C, C++)도 있다
- 배열 대신 컨테이너를 사용하거나 배열을 순차적인 구조체로 생각하라
- 배열의 마지막 위치를 확인
- 다차원 배열에서 첨자의 순서가 정확한지 확인
- 인덱스가 혼선(Cross-Talk)되지 않도록 주의
- 예) Array[i] 와 Array[j]
- C 또는 C++에서는 ARRAY_LENGTH 매크로를 사용
#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0])
float consistency_ratio[] = {
0.0, 0.0, 0.58, 0.90, 1.12,
…
1.59
};
…
for (ratioIdx = 0; ratioIdx < ARRAY_LENGTH(consistency_ratio) ; ratioIdx++) {
…
}
변수 사용시 일반적인 문제
능률적인 변수 정의 방법
- 다른 모듈에서 정의한 변수를 사용하려면 반드시 선언
- 선언(Declaration)
- 정의(Definition)
- 명명 규약(Naming Convention)을 사용
- 변수의 이름을 검사
부적절한 변수 초기화
- 변수에 값을 할당한 적이 없다
- 더 이상 유효하지 않은 변수에 값을 할당
- 변수의 일부에 값을 할당하고 나머지는 할당하지 않는다
변수 초기화
- 변수가 정의될 때 초기화
- 변수가 처음 사용되는 곳에 근접한 위치에서 정의 및 초기화
- 가능하면 const 또는 final을 사용
- 카운터와 누산기를 조심
- 재사용 전에 반드시 초기화
- 객체의 데이터 필드는 생성자에서 초기화
- 변수를 다시 초기화할 필요가 있는지 검사
- 반복문과 변수 사용시 주의
- 상수를 흉내내기 위한 변수들은 Startup() 루틴에서 한번만 초기화
- 모든 변수를 자동으로 초기화해주는 컴파일러 설정 사용
- 컴파일러 경고 메시지를 활용
- 입력 인자의 타당성 검사
- 부적절한 포인터를 검사하기 위해서 메모리 접근 도구 사용
- Memory Leak Detection Tool 사용
- 프로그램 시작시에 작업 메모리를 초기화
- NULL(0), 0xCC(Intel CPU에서)
변수의 범위
- 변수에 대한 참조는 지역화
- 동일 변수에 대한 참조는 되도록 가깝게 유지
- 변수들의 폭을 좁게 유지
- 변수의 (평균) 폭이 작을수록 프로그램의 가동성이 좋다
[ 좋은 예시 ] a = 0; b = 0; c = 0; a = b + c; [ 안좋은 예시 ] a = 0; b = 0; c = 0; b = a + 1; b = b/c; |
- 변수의 수명을 가능한 짧게 유지
- 수명이 짧은 변수는 코드를 읽기 쉽고 변수의 잘못된 사용을 막는다
변수의 범위를 최소화하기 위한 지침
- 루트(반복문)에서 사용되는 변수는 루트 바로 직전에서 초기화
- 변수를 사용하기전까지는 변수에 값을 할당하지 않는다
- 연관된 명령문을 그룹화
- 연관된 명령문을 별도의 루틴으로 나눈다
- 처음에는 가시도를 제한하고 필요한 경우에만 가시도를 넓힌다
- private → protected, package, pulic
변수의 지속성(수명)
- 특정 코드 블록이나 루틴에서만 살아남은 경우
- 코드 블록 또는 루틴에서 정의된 변수에 해당
- 허용된 동안 살아남은 경우
- new를 이용하여 생성한 객체는 delete(C++) 또는 가비지 컬레션(Java)때까지 살아남는다
- 프로그램이 종료할 때까지 남는 경우
- static 변수 (C, C++, Java)
- 지역변수
- 영원히(Persistent) 살아남는 경우
- 데이터베이스 또는 파일에 값을 저장하는 변수
바인딩 시간(Binding Time)
- 변수와 그것의 값이 서로 연결되는 시간
- 코드 작성시 바인딩(리터럴)
- 컴파일시 바인딩
- 실행시 바인딩
- 레지스트리 또는 파일 사용
- 객체 생성시
- 적시(Just in Time)
- 예)윈도우를 화면에 그릴 때
- 바인딩 시간이 이를수록(늦을수록) 유연성과 복잡성이 낮아진다(높아진다)
변수 사용시 주의할 점
- 각 변수는 한가지 목적만을 위해 사용
- 숨겨진 의미를 갖는 변수를 피하라
- pageCount 변수는 값이 출력된 페이지 수를 표현한다. -1인 경우 오류를 표시한다.
- bytesWritten 변수는 출력 파일에 쓰여진 바이트 수이다. 하지만 이 값이 음수면 출력 파일에 사용된 디스크 드라이브의 수를 가리킨다.
- 정의된 모든 변수가 사용되는지 확인
[ 안좋은 예시 ] temp = sqrt(b*b-4*a*c); root[0] = (-b+temp) / (2*a) root[1] = (-b-temp) / (2*a) … temp = root[0]; root[0] = root[1]; root[1] = temp; |
[ 좋은 예시 ] discriminant= sqrt(b*b-4*a*c); root[0] = (-b+discriminant) / (2*a) root[1] = (-b-discriminant) / (2*a) … temp = root[0]; root[0] = root[1]; root[1] = temp; |
변수의 명명
명명 규칙의 필요성
- 다수의 개발자에 의한 공동작업을 수행하는경우
- 다른 개발자가 작성한 코드를 검토하거나 유지 보수하는 경우
- 프로그램을 부분적으로 생각하고자할 때
- 시일이 지난후 자신이 작성한 코드를 다시 검토할 때
- 특이한 용어들이 많아서 코드 작성시 표준 용어 또는 약어가 필요한 경우
좋은 변수이름을 위한 고려 사항
- 변수의 의미를 완벽하고 정확하게 설명해야 한다
변수 의미 | 좋은 이름 | 나쁜 이름 |
날짜가 쓰인 유통중인 수표의 총계 | runningTotal, checkTotal | written, ct, checks, CHKTTL, x, x1, x2 |
고속 열차의 속도 | velocity, trainVelocity, velocityInMph | velt, v, tv, x, x1, x2, train |
현재 날짜 | currentDate, todaysDate | cd, current, x1, x2, date |
페이지당 행의 수 | linesPerPage | lpp, lines, x1, x2, l |
- 해결하고자 하는 문제 영역의 개념을 표현
- 예) 직원 데이터는 inputRec 보다는 employeeData를 사용, 프린터의 상태 표시하는 프래그는 bigFlag 보다는 printerReady를 사용
- 적절한 길이를 사용
- Too shart : 의미 불명확
- Too Long : 입력 불편, 코드 구조 파악 불편
- 짧은 변수는 Loop 카운터 또는 배열인덱스를 위해 사용
- 예) i, j, k 등
너무 길다 | numberOfPeopleOnTheUsOlympicTeam numberOfSeatsInTheStation maximumNumberOfPointsInModernOlympics |
너무 짧다 | n, np, ntm N, ns, nsisd M, mp, max, points |
적당 | numTeamMembers, teamMemberCount numSeatsInStadium, seatCount teamPointsMax, pointsRecord |
- 이름 공간(Namespace)(C++)를 사용하여 변수 이름 충돌을 회피 (Java는 Package 사용)
- 한정자는 주로 변수의 끝에 위치시킨다
- 앞부분의 중요한 의미를 전달하도록
- 일관성을 유지하여 혼돈을 방지
- totalRevenue ↔ revenueTotal
- 대칭적 이름을 작성하기에 유리
- revenueTotal/expenseTotal, revenueAverage/expenseAverage 는 totalRevenue/totalExpense, averageRevenue/averageExpense 보다유리
- 일반적인 반의어의 조합을 사용
- begin/end, first/last, locked/unlocked, min/max, next/previous, old/new, opened/closed, visible/invisible, source/destination, up/downsource/target, source/destination, up/down
변수명의 축약 - 일반적 지침
- 표준 축약어를 사용 (사전에나오는)
- 불필요한 모음을 제거
- 예) computer → cmptr, screen → scrn
- 관사 및 접속사(a, the, and, or 등)는 제거
- 각 단어의 첫 문자 또는 처음 몇개의 문자를 사용
- 각 단어의 첫 번째와 두 번째, 세 번째 다음에 오는 것을 일관성 있게 자른다
- 각 단어의 처음과 마지막 문자를 유지
- 이름에서 가장 중요한 단어를 최대 세 단어까지 사용
- 쓸모없는 접미사(ing, ed 등)를 제거
- 각 음절에서 가장 뚜렸한 소리를 유
- 변수의 의미가 변경되지 않도록 주의
- 위의 기법을 반복적으로 적용
- 음성축약 ← 비추천
- highlight → hilite, before → b4, excute → xqt
축약시 주의할 점
- 단어에서 한 문자를 없애는 방법으로 축약하지 말라 → 노력의 감소에 비해가독성이 떨어짐
- 예) June → Jun
- 일관성 있게 축약
- 발음할 수 있는 이름으로 생성
- 예) XPstn → xPos, ndsCmptg → needsComp
- 잘못된 발음으로 인한 조합을 피한다
- 예) 마지막 B를 나타내기 위해 BEND 보다는 ENDB, B-END, BEnd, b_end를사용
- 축약시 이름의 충돌을 방지하기 위해 동의어 사용
- 예) fired와 full revenue disbursal이 frd로 축약될 수 있음, 이경우 fired → dismissed → dsm, full revenue disbursal → complete revenue disbursal → crd
- 매우 짧은 이름은 코드 내에 변환 테이블을 사용하여 문서화
- 모든 축약어는 프로젝트 수준의 표준축약어 문서에 기록
'Memo' 카테고리의 다른 글
JEB java.lang.NullPointerException 오류 해결 방법 (0) | 2020.07.19 |
---|---|
Git 사용법 (0) | 2020.06.21 |
Python(.pyc) 디컴파일 (0) | 2020.05.01 |
CTF 풀 때 도움 되는 사이트 정리 (0) | 2020.04.13 |
GitHub 사용법 (0) | 2020.04.13 |