소닉붐 코드 수정하기

김윤기·2025년 9월 2일

바쁜 개발 도중이다 보면 다음과 같이 소닉붐 모양의 코드가 나오기 마련이다.

소닉붐 if문 코드

이러한 코드 형태는 여러 가지 문제점을 만든다.

  1. 디버깅의 어려움
  2. 코드 이해의 어려움
  3. 유지보수의 어려움
  4. 새로운 기능 추가의 어려움

내 생각에 개발의 80%는 디버깅과의 싸움이라고 본다.

어디서 오류가 발생했는지, 문제가 무엇인지 정확히 파악하지 못한다면 신기능은 출시하지 못하고, 디버깅에 시간을 소모하면서 일정이 점점 늦어지는 경험을 하게 된다.

경험상 잘 동작하던 코드에 새로운 기능을 추가할 때마다 새로운 문제가 하나씩 드러나곤 한다.

code bird

일단 정상적으로 동작하더라도 점차 다른 문제가 커져 간다.

그렇다면 어떻게 해결하는 것이 좋을까?

그 답은 공식 코드와 C 언어에서 찾을 수 있다.
리눅스 커널의 file.c 프로그램을 참고해보자.

에러 체크를 먼저 수행하고 이후 로직을 실행하는 구조를 확인할 수 있다.

int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
{
	int new_fd;
	int error;

	error = security_file_receive(file);
	if (error)
		return error;

	new_fd = get_unused_fd_flags(o_flags);
	if (new_fd < 0)
		return new_fd;

	if (ufd) {
		error = put_user(new_fd, ufd);
		if (error) {
			put_unused_fd(new_fd);
			return error;
		}
	}

	fd_install(new_fd, get_file(file));
	__receive_sock(file);
	return new_fd;
}

예를 들어, 인수의 상태를 차례대로 검사하고 처리한다면 가독성이 좋아지고 오류를 찾기도 쉬워진다.

반환값 함수(인수1, 인수2...) {

	// 인수의 상태 검사
	if ( 인수1 == 0 )
		return -1
		
	// 인수의 상태 검사
	if ( 인수2 == 0 )
		return -1
}

그렇다면 왜 이렇게 이해하기 쉬운 코드를 추구해야 하는가?

그 이유는 인간의 인지적 한계와 소통 능력으로 설명할 수 있다.

아무리 똑똑한 사람이 코드를 작성하더라도,
이후에 이 코드를 유지보수할 사람은 그렇지 않을 수도 있다.
심지어 멍청할 수도 있으며,
처음 작성자의 의도를 다른 사람들이 그대로 이해할지도 아무도 모른다.

바로 이런 인지적 한계와 소통 능력 때문에 더욱 소통이 원활하고 인지적 부하를 줄이는 코드를 선택해야 한다.

인지적 부하에 대해 잘 정리한 글이 있어 함께 공유한다.

cognitive-load

나는 실제로 프로그래밍 코드를 ‘아름답게’ 만들고 싶었고, 그 결과 현재의 순차적인 흐름이 이해하기 쉽게 잘 나타나는 코드가 ‘아름다운’ 코드라고 생각한다.

솔직히 클린 코드를 정독해본 적은 없지만, 그 책에서 강조하는 핵심 내용도 크게 다르지 않다고 본다. 다만 세상 일에 정답이 없듯, 지나치게 단순한 로직을 억지로 함수화하는 것은 오히려 위험할 수 있다.

예를 들어, 다음과 같은 함수를 생각해보자.

bool validIsZeroNumber(int number) {

	if( number == 0 ) {
		return false
	}
	
	return true
}

이 함수의 장점은 함수명이 의미를 명확히 전달하고 코드도 깔끔하다는 점이다.
그러나 실제로 사용하면 변수명이 지나치게 장황해지고,
오히려 함수의 역할이 모호해질 수 있다.

차라리 이렇게 직접 작성하는 편이 낫다.

''' 나의 코드

if ( number == 0) {
	printf("아무 값이 없어요")
	return -1
}
	
''' 나의 코드

줄 수나 길이가 함수화한 경우와 크게 다르지 않으면서도 의미가 명확하고 훨씬 간단하다.

물론 두 방법이 모두 틀렸다고 말할 수는 없다. 하지만 나는 후자의 방식이 더 실용적이고 이점을 많이 가져올 수 있다고 생각한다.

컴퓨터 구조적으로 보아도 함수 호출은 생각보다 오버헤드가 크다.

프로그램 코드는 실제 실행 시에는 차례대로 기록된 명령어를 따라간다.

함수를 호출하면 스택(stack) 영역에 이전 프로그램의 주소와 지역 변수를 저장하고, 새 함수로 이동해야 한다.

이 과정에서 불필요한 메모리 참조와 데이터 이동이 발생한다.

물론 이는 C 언어의 관점이지만, 다른 언어에서도 함수 호출은 유사한 방식으로 주소 이동을 자주 일으킨다.

하지만, 현대의 모던 컴파일러는 자동 최적화를 수행하므로, 일반적 애플리케이션에서는 함수 호출 오버헤드에 큰 신경 쓸 필요 없다는 주장도 있다.

그러나, 몇 번 사용하지 않는 코드라면 굳이 함수화하지 않고 고정해 두는 편이 가독성 측면에서 유리하다.

그러나 inline 함수의 장점과 단점을 함께 공유해 궁극적으로는
정확히 필요한 부분인지, 정말 필수적인 부분인지 따져보아야 한다.

리누스 토르발즈의 말처럼, 단순히 눈앞의 문제를 임시로 해결하려고 함수를 남발하기보다,
실제 존재하는 문제가 무엇인지 파악하고 본질적인 부분만 해결하는 것이 진정한 답이 아닐까 한다.

profile
글을 잘 쓰고 싶은 개발자 ✨

0개의 댓글