News Feed

개발의 함정을 피하는 7가지 실전 코딩 원칙

컨텐츠 정보

  • 조회 364

본문

소프트웨어 개발은 위험으로 가득하다. 어떤 개발 작업이든 잘못할 수 있는 방법은 수없이 많지만, 올바른 방법은 조용히 숲속을 가로지르는 좁은 오솔길과 같다. 그 길을 알고 위험한 함정을 피하려면 경험이 필요하다.

다음은 필자가 어두운 숲속을 여러 차례 헤쳐 나가며 얻은 7가지 교훈이다. 애플리케이션 코드를 작성할 때 해야 할 일과 해서는 안 될 일을 경험적으로 정리한 조언이다. 잘못된 길로 새는 것은 너무도 쉽지만, 아래의 원칙들을 따르면 시행착오와 실수를 최소화하며 목적지에 안전하게 도달할 수 있을 것이다.

이 조언을 잘 따라가면 덤불에 걸리지 않는다.

일방통행 도로에서도 양쪽을 모두 보라

영국에서는 도로의 ‘반대쪽’으로 운전한다. 영국인은 외국인이 이 사실을 항상 인지하지는 않는다는 점을 잘 알고 있다. 그래서 런던의 횡단보도에는 보행자에게 ‘오른쪽을 보라(Look right)’는 문구가 도로 바닥에 큼지막하게 적혀 있다. 미국식 운전에 익숙한 필자로서는 늘 왼쪽을 먼저 보기 때문에, 그 안내 문구가 유용했다.

하지만 습관은 쉽게 바뀌지 않았다. 결국 필자는 왼쪽과 오른쪽, 양쪽을 모두 보게 되었다.

이 습관은 코딩에도 좋은 비유가 된다. ‘불가능한 일’을 대비하는 것이다. 그것은 언젠가 실제로 일어날 수도 있다. 코드는 늘 예상치 못한 방식으로 변하며, 반드시 변화한다. 지금은 어떤 정수형 변수가 절대 0보다 작을 리 없다고 생각할 수 있지만, 미래의 누군가가 그 코드를 바꿔버릴 가능성을 배제할 수는 없다.

‘불가능’에 대비하는 코드는 결국 ‘가능’을 걱정하지 않아도 되는 코드다.

한 가지가 두 가지 일을 하게 하지 마라

개인적으로 가장 큰 불만이자 흔한 문제다. 하나의 요소에 두 가지 역할을 맡기는 순간, 문제가 끝도 없이 이어진다.

루틴 안에서 변수를 다른 용도로 재활용하고 싶은 유혹이 들 때, 절대 그러지 말라. 그냥 변수를 하나 더 선언하라. 매개변수로 전달된 플래그 값에 따라 두 가지 기능을 수행하도록 함수를 설계하고 싶다면, 차라리 두 개의 함수를 작성하라. 클래스에서 다섯 가지 다른 쿼리를 실행하도록 스위치문(switch statement)을 만들 생각이라면, 각 쿼리마다 별도의 클래스를 만들고 팩토리 패턴(factory pattern)을 사용해 적절한 클래스를 생성하라.

조금 더 많은 코드가 필요하더라도, 한 가지가 두 가지 일을 하도록 만드는 복잡성은 훗날 반드시 문제를 일으킨다. ‘엉클 밥(Uncle Bob)’의 표현을 빌리자면, 하나의 객체에 둘 이상의 책임을 지게 하는 설계는 언젠가 재앙을 부른다.

코드는 구현이 아니라 인터페이스에 맞춰 작성하라

애플리케이션 코드를 특정 구현에 결합시키는 일은 쉽고도 흔하다. 예를 들어 로그를 모두 텍스트 파일로 남기도록 애플리케이션을 설계했다고 하자. 초기에는 잘 작동하지만, 곧 여러 대의 머신에서 애플리케이션이 돌아가면서 텍스트 파일이 여기저기 흩어지고 추적과 관리가 어려워진다. 중앙 데이터베이스로 로그를 모으기로 결정하는 순간, 텍스트 파일에 쓰던 방식을 데이터베이스에 쓰도록 바꾸는 일이 결코 작지 않다는 사실을 깨닫게 된다.

처음부터 로깅 시스템을 인터페이스에 맞춰 코딩했다면 어땠을까? 위와 같은 문제가 생겼을 때 로깅 인터페이스의 새 구현을 하나 작성해 꽂아 넣기만 하면 된다. 그러면 끝이다. 문제는 곧바로 해결된다.

새 구현을 인터페이스에 연결하는 일은 애플리케이션 깊숙이 뿌리내린 결합된 구현을 들어내는 일보다 언제나 더 쉽다. 촘촘히 얽힌 촉수를 일일이 끊어낼 필요가 없기 때문이다.

설명 변수를 두려워하지 말라

다음 코드를 보자.

if (  (user.age > 18 && user.hasValidID) &&  (!user.isBanned || user.hasAppealPending) &&  (currentDate >= event.start && currentDate 

이 코드는 복잡하고, 이해하기가 정말 어렵다. 각 불리언(Boolean) 표현식을 정신적으로 풀어 읽어야 하고, 괄호 속에서 무슨 일이 벌어지는지 계속 추적해야 한다. 번거롭고 파악하기가 힘들다.

다음 코드는 훨씬 이해하기 쉽다.

const isAdultWithID = user.age > 18 && user.hasValidID;const isAllowedDespiteBanStatus = !user.isBanned || user.hasAppealPending;const isEventOngoing = currentDate >= event.start && currentDate 

복잡한 불리언 조건에 설명력을 가진 이름을 붙이면, 특정 사용자가 조건을 충족하는지 아닌지의 개념이 훨씬 분명해진다. 그러니 주저하지 말라.

사소한 오류를 가차 없이 제거하라

필자는 코딩할 때 이 원칙을 철저히 따른다. 주석의 오타를 허용하지 않는다. 사소한 포맷팅 불일치도 용납하지 않는다. 사용하지 않는 변수는 제거한다. 주석 처리된 코드는 코드 베이스에 남겨두지 않는다. 사용하는 언어가 대소문자를 구분하지 않더라도, 코드에서 일관되지 않은 대소문자 표기는 허용하지 않는다.

작은 것들을 바로잡으면, 더 큰 문제는 스스로 정리된다.

암시는 해롭다

지금도 이해하기 어렵다. 왜 일부 개발자는 암시적인 방식을 미덕으로 볼까? 더 분명할 수 있는데 굳이 덜 분명한 방식을 택하는 선택이 놀랍다.

암시는 인지 부하를 키운다. 코드가 암시적으로 동작하면, 개발자는 컴파일러가 무엇을 할지 멈춰 서서 추측해야 한다. 기본값 변수, 숨겨진 변환, 감춰진 부작용 같은 요소는 코드를 이해하기 어렵게 만든다.

사람은 늘 정확히 맞힐 수 없다. 추측할 필요가 없도록 모든 것을 명시적으로 만들어 두면, 더 좋은 코드가 된다.

범위를 최대한 좁혀라

모두가 알고 있거나, 적어도 알아야 할 사실이 있다. 전역 변수(global variable)는 절대 사용하지 말아야 한다는 것이다. 전역 변수는 너무 쉽게 통제를 벗어나며, 예기치 않은 곳에서 변경되고, 이유를 알 수 없는 이상한 값을 갖게 되기 때문이다.

다시 말해, 전역 변수의 범위(scope)가 지나치게 넓다는 점이 문제다. 따라서 범위를 제한하라는 원칙은 곧 전역 변수를 피하라는 말과 같다.

이 원칙은 훨씬 더 넓게 적용된다. 클래스 내부의 필드 역시 가능한 한 접근 범위를 제한해야 한다. 가능하다면 private 접근자를 사용하라. 프로그래밍 언어가 인라인 변수(inline variable) 선언을 지원한다면, 변수를 최대한 늦게 선언하라. 불필요한 변수들이 엉뚱한 곳에서 접근되거나 조작되지 않도록 가시성을 줄여야 한다.

여기서 살펴 본 방법은 코드를 안정적으로 통제하는 데 도움이 된다. 이런 교훈은 직접 잘못된 코드를 작성해본 경험, 그리고 그보다 더 자주 겪게 되는, 이런 원칙을 배우지 못한 이들이 남긴 코드를 유지보수하면서 얻은 값비싼 경험에서 비롯된 것이다.

이런 습관을 따른다면, 가시덤불로 가득한 개발의 오솔길을 훨씬 수월하게 걸어갈 수 있을 것이다.
dl-itworldkorea@foundryco.com

관련자료

댓글 0
등록된 댓글이 없습니다.