콘텐츠로 이동

코딩과 디버깅

정확하고 효율적인 코드를 작성하기 위한 원칙과 흔히 발생하는 실수들을 정리했습니다.


1. 좋은 코드를 짜기 위한 원칙

간결한 코드 작성

코드가 짧을수록 오타나 단순 버그가 발생할 확률이 줄어들고 디버깅이 쉬워집니다. 전역 변수 사용은 코드 구조가 단순한 상황(대회 등)에서는 허용될 수 있습니다.

적극적인 코드 재사용 (모듈화)

같은 코드가 3번 이상 등장한다면 함수로 분리하세요. 당장은 번거로울 수 있지만, 깔끔한 코드를 유지하는 습관은 장기적으로 코딩 속도와 정확도를 높여줍니다.

표준 라이브러리 활용

자료구조나 정렬 알고리즘을 직접 구현하는 것은 시간 낭비입니다. 이미 검증된 표준 라이브러리를 사용하여 메모리 관리와 정당성 고민을 덜어내세요.

일관된 코딩 스타일 유지

자주 사용하는 알고리즘이나 패턴은 항상 같은 형태로 작성하는 것이 좋습니다. 검증된 템플릿을 사용하면 문제의 핵심 로직에 더 집중할 수 있습니다.

명확한 명명법 (Naming)

모호하지 않은 변수명과 함수명을 사용하세요. 명확한 이름은 잠재적인 로직 오류를 방지합니다.

자료의 정규화 (Normalization)

같은 자료는 하나의 형태로만 표현되도록 하세요. (예: 기약 분수로 유지, 각도를 0~360도 범위로 고정) 표현 방식이 여러 개일 경우 미묘한 버그의 원인이 됩니다.

코드와 데이터의 분리

로직과 무관한 데이터는 배열이나 설정 파일로 분리하여 관리하세요.

// Bad
if(month == 1) return "January";

// Good
const string monthName[] = { "January", "February", ... };


2. 자주 하는 실수 (Mistakes)

  • 산술 오버플로: 변수의 표현 범위를 넘어서는 계산 주의 (특히 곱셈).
  • 배열 범위 초과: IndexOutOfBounds 오류 주의.
  • 일관되지 않은 범위 표현: 가급적 반 열린 구간(Half-open interval) [start, end) 방식을 일관되게 사용하세요.
  • Off-by-one 오류: 하나가 더 많거나 적게 계산되는 문제 (예: 울타리 기둥 개수). 최소 입력값으로 검증하면 효과적입니다.
  • 컴파일러가 잡지 못하는 오타: 대소문자, 숫자 0의 개수, 상수값 오타 등.
  • 스택 오버플로: 너무 깊은 재귀 호출 주의.
  • 다차원 배열 인덱스 혼동: arr[i][j]arr[j][i]를 바꿔 쓰는 경우.
  • 잘못된 비교 함수: 표준 라이브러리의 비교 연산 규칙을 정확히 숙지하세요.
  • 최소/최대 예외 처리: 입력의 경계값(Boundary cases)에서 코드가 정상 동작하는지 확인합니다.
  • 연산자 우선순위: 헷갈릴 때는 명시적으로 괄호 ()를 사용하세요.
  • 느린 입출력: 데이터 양이 많을 때는 해당 언어의 가장 빠른 입출력 방식을 사용하세요.
  • 변수 초기화 미비: 여러 테스트 케이스를 처리할 때 전역 변수 초기화 여부를 반드시 확인하세요.

3. 디버깅과 테스팅

디버깅 전략

  • 눈으로 디버깅하기: 코드를 한 줄씩 읽으며 검증합니다. 기능적으로 잘 분리된 코드는 눈으로도 충분히 검증 가능합니다.
  • 작은 입력으로 테스트: 수동으로 결과를 확인할 수 있는 작은 입력값을 활용합니다.
  • 단정문 (Assertion) 활용: assert(condition)을 통해 프로그램 내부 상태를 상시 검증합니다.
  • 중간 결과 출력: 계산 중간값을 출력하여 문제 발생 범위를 좁힙니다.

테스팅 기법

  • 경계값 테스트: 가장 작은 입력과 가장 큰 입력을 반드시 넣어봅니다.
  • 스캐폴딩 (Scaffolding): 테스트를 위해 임시로 작성하는 보조 코드를 활용하여 복잡한 로직을 검증합니다. (단, 과도한 시간 소모는 주의)