키워드를 위장한 이름
문서화할 때는 “file”과 같이 파일명을 표시해야 하고 “Charlie. dat” 또 는 “Frodo.txt”처럼 파일명을 명백히 표시하지 말아야 한다. 되도록 예 약어처럼 보이는 이름을 사용하는 것이 좋다. 예를 들어, “bank”, “blank”, “class”, “cons”, “constant”, “input”, “key”, “keyword”, “kind”, “output”, “parameter” “parm”, “system”, “type”, “value”, “var” 그리고 “variable” 등을 매개변수나 변수명으로 사용해야 한다. 실제 예약어를 임의고 사용하면 명령어 프로세서나 컴파일러가 처리를 거부할 수 있다. 이를 잘 활용하면 사용자는 우리가 만든 임의의 이름과 예약어를 혼동하게 만들 수 있다. 누군가 딴지를 걸면, 사용자 가 각 변수의 이해를 적절히 돕기 위해 사용한 것이라고 발뺌하면 그만이다.
코드에 사용한 이름은 화면 표시 이름과 달라야 한다
화면에 표시되는 값과 변수명은 전혀 관련이 없도록 해야 한다. 예를 들어, 화면에는 “Postal Code”로 표시되는 변수의 이름을 “zip”과 같이 색다르게 정할 수 있다.
이름을 변경하지 마라
전체적으로 이름을 바꾸는 방법으로 두 섹션 코드를 동기화하는 것보다는 같은 심 볼에 여러 TYPEDEF문을 사용하는 것이 바람직하다.
금지된 지역변수를 감추는 방법
전역 변수는 “악”과 같은 존재이므로 전역적으로 사용할 모든 데이터를 저장할 구조체를 정의하고 EverythingYoullEv-er Need와 같이 똘똘한 이름을 붙여준다. 모든 함수가 이 구조체에 대한 포인터(포인터면은 handle이라고 함으로써 혼란을 더할 수 있다)를 갖게 할 수 있다. 실제로는 “handle”을 통해 전역 변수를 마음껏 사용하면서 다른 이에게는 우리가 전역 변수를 사용하지 않는다는 인상을 줄 수 있다. 전역 변수를 사용하는 모든 코드에서 정적 변수를 선언하는 것도 좋은 방법이다.
동의어로 인스턴스 숨기기
유지보수 프로그래머가 뭔가를 수정하고 그로 인해 발생할 수 있는 부수 효과를 확인할 때 일반적으로 프로그램 전체에서 사용된 변수명을 검색할 것이다. 동의어 사용이라는 간단한 방법으로 이러한 유지보수 프로그래머의 시도를 좌절시킬 수 있다. 서로 다른 include 파일에 흩어놓아야 한다. 특히 include 파일이 서로 다른 디렉터리에 위치한 경우 효과적이다. 가능한 모든 범위에서 이름을 재사용하는 기법도 있다. 컴파일러는 정확하게 모든 이름을 구별할 수 있겠지만, 단세포적인 텍스트 검색기로는 이름을 구별하기 어려울 것이다. 불행하게도 SCIDSource Code in Database가 점점 발전하면서 편집기가 컴파일러처럼 범위 규칙을 이해하게 되면 간단한 기법은 더 이상 사용할 수 없게 될 것이다.
길고 비슷한 변수명
변수명이나 클래스면은 되도록 길게 만들고 두 개 이상의 이름이 필요할 경우 한 글자만 바꿔놓거나 대소문자만 다르게 한다. 변수명 swimmer와 swimner는 좋은 예다. 대부분의 폰트로는 ilI1|나 OO 08을 명확하게 구별하기 어렵다는 점을 악용하자. 예를 들어, parselnt와 parseInt 혹은 D0 Cal과 DOCalc를 명확히 구분하기 어렵다. 이 중에서도 l은 얼핏 보기에 1과 구별하기 힘들기 때문에 변수명으로 사용하기 가장 좋은 알파벳 중 하나다. 그뿐만 아니라 대부분의 폰트에서 Rn은 m처럼 보이는 경우가 많다. 따라서 swimmer와 쉽게 구별하기 어려운 swirnrner 도 좋은 변수명이다. Hash Table과 Hash table처럼 한 글자의 대소문자만 살짝 변경해서 변수명을 만드는 것도 좋은 방법이다.
비슷하게 발음되고, 비슷하게 보이는 변수명
XY_z라는 변수명 이외에 XY_Z, XY_ _z, _XY_z, _xyz, XY_Z, XY_z, XY_z처럼 다양한 변수명을 사용하지 말라는 법은 없다. 때로는 변수명을 소리 나는 대로 혹은 스펠링으로 기억하는 프로그래머를 많이 볼 수 있는데 대소문자나 밑줄로만 구별되는 변수명이 이들을 혼란에 빠뜨릴 것이다.
오버로드 그리고 당황
C++에서 #define을 사용해 라이브러리 함수를 오버로드하자. 얼핏 보면 친숙한 함수를 쓰고 있는 것처럼 보이겠지만 사실은 완전 다른 기능을 하게 할 수 있다.
효율적인 오버로드 연산자 선택하기
C++에서 +, -, *, / 등과 같은 연산자를 사칙 연산의 의미와 전혀 관련 없는 동작을 하도록 오버로드하자. 스트로우스트 룹Stroustroup도 쉬프트 연산자를 I/O에 사용했는데 우리도 그처럼 창의적이지 못할 이유가 없지 않은가? +을 오버로드할 때는 “i = i + 5;”가 “i += 5;”와 같은 의미를 갖지 않도록 해야 한다. 최첨단 연산자 혼란 오버 로딩 기법을 소개하겠다. 클래스의 ‘!’ 연산자를 오버로드하면서 뭔가를 뒤집거나 부정하는 동작과는 아무 관련이 없는 동작을 하게 하는 것이 핵심이다. ‘!’ 연산자가 정수를 반환하게 한다. ‘!’를 논리 연산자고 사용하려면 ‘! !’로 표기해야 한다. 그러나 ‘!’ 연산 자체가 로직을 변경시키므로 결국 하나를 더 붙여서 ‘! ! !’ 을 사용해야 한다. 여기서 말하는! 연산자는 불린 값 0이나 1을 반환하는 연산자로 비트 단위의 논리 부정 연산자 ~와 혼동하지 말자.
new를 오버로드하라
“new” 연산자를 오버로드하라. 이는 +-/*을 오버로드하는 것보다 훨씬 위험하다. 기존 함수를 뭔가 다른 기능(그러나 오브젝트의 기능에 필수적인 함수이므로 변경하기 쉽지 않다)으로 오버로드한다면 큰 혼란을 야기할 수 있다. 사용자가 동적인 스텁스를 생성할 때 온전한 인스턴스가 아닌 잘려 나간 인스턴스 조각만 얻게 하 는 것이 핵심이다. “New”라는 멤버 변수를 추가하므로 대소문자를 이용한 혼란 기법을 가미할 수 있다.
#define
C++의 소스 코드 판독을 어렵게 하는데 #define의 활용도는 무궁무진해서 이에 대한 내용만 따로 집필할 수 있을 정도다. 소문자로 된 #define 변수로 원래 변수를 대체할 수 있다. 선처라 함수에는 절대 파라미터를 사용하지 말아야 한다. 전역 #define으로 원하는 모든 기능을 수행하자. 누군가는 #define을 활용해서 실제 컴파일이 이루어질 때까지 CPP를 다섯 번 통과하게 했다고 한다. 필자가 들어 본 사례 중 가장 창의적인 활용 방법이다. 똘똘하게 define과 if def를 사용해 각에 더 파일에서 몇 번이나 해당 구문을 include 했느냐에 따라 결과가 달라지게 할 수 있고, 이로써 코드는 혼란의 경지에 이르게 된다. 이제 얼마나 많이 헤더를 include 했느냐에 따라 결과가 달라지므로 g() 함수에 char*을 전달해 호출하면 어떤 재미있는 일이 벌어지는지 구경하는 일만 남았다.
컴파일러 지시어
컴파일러 지시어는 같은 코드를 상황에 따라 다르게 동작하도록 만들어졌다. Boolean 쇼트서킷 지시어와 long strings 지시어를 반복적으로 줄기차게 껐다 켜기를 반복하자.
데이터 통신
변수명 찾기 어렵게
반응형
반응형
댓글