728x90

파일 헤더를 제공하라
사소하지만 꽤 중요하다. 난 지금까지 제대로 지키지 않았다. 앞으로는 잘 하도록 노력해야겠다. 대부분의 회사에서는 법률적인 이유로 모든 소스 파일에 가시적인 저작권 공지를 포함시키도록 의무화하고 있단다.
/*************************************
* 파일 : FileName.java
* 목적 :
* 알림 : 저작권표시
*************************************/

에러를 적절하게핸들링하라
에러는 발생한 곳과 가까운 곳에서 처리하는 것이 좋다. 에러가 발생하면 어디서 왔는지, 에러의 이유가 무엇인지, 에러가 발생한 것은 무엇을 의미하는 것인지 알기 쉽도록 해라.(어떻게? 잘~)

의미 있는 코멘트를 작성하라
학교에서 처음 프로그래밍을 배우면서 코드를 작성하고 발표수업이 있을 때 모든 문장에 코멘트를 달도록 강요받은 기억이 있다. 코멘트가 너무 많은 코드는 오히려 보기 불편하다. 가능하면 코멘트가 필요없도록 작성하되 그러고도 남아있는 부분에 대해서는 적절한 분량의 코멘트를 추가해야 한다.
* 파일헤더, 함수의 설명, 변수에 대한 설명은 가능하면 생략하지 마라.


문서화의 여러가지 방법


문학적 프로그래밍(프로그램을 작성하지 말고, 문서를 작성하라. 소설처럼 써라.)
장점

* 문학적 프로그래밍은 문서작성에 강점을 둔다.
* 문서가 가까이 있으므로 업데이트할 때 문서도 함께 업데이트 하기 쉽다.
* 전체 코드베이스에 대해 단 하나의 문서만 존재한다는 사실이 보장된다.(코드 자체가 문서기 때문)
* 일반적으로 코멘트에 쓰이지 않는 항목도 문서화하도록 유도한다.(사용된 알고리즘에 대한 설명, 코드가 올바르다는 증명, 그렇게 설계하게 된 결정의 정당성.)
* 유지보수에서 빛이 난다.
단점
* 코드가 아니라 문서 전체를 작성해야 하므로 대부분의 프로그래머들이 힘들고 귀찮아 한다.
* 또 하나의 컴파일 단계가 필요하고, 그것이 작업 속도를 느리게 만든다.(아직 바로 컴파일해줄만한 툴은 없단다. 당연하지!)
* 정말 문서화가 필요하지 않은 부분까지도 문서화하게 될지도 모른다. 또는 일부를 문서화하지 않게 될지도 모른다. 귀찮으면 아예 하지 않는 것이 좋다. 이도저도 아니면 안된다.
* 프로그램 잘 짠다고 글도 잘쓰는 것은 아니다. 훌륭한 프로그래머라고 해서 반드시 유능한 문학적 프로그래머가 되는 것은 아니다.


문서화툴
문서화를 도와주는 툴이 많이 있다는 말이다. 책에서는 Javadoc를 예로 들었는데 이는 다음과 같은 일을 도와준다.
 * 저작권 정보를 명시한다
 * 생성일자를 기록한다
 * 정보를 상호 참조시킨다
 * 오래된 코드에 deprecated라고 표시한다.(오래됐다고 바꾸라고 권장한다는 뜻)
 * 빠른 참조용의 짤막한 개요(synopsis)를 제공한다
 * 함수 파라미터 각각에 대한 설명을 제시한다
javadoc, C#의 NDoc와 Doxygen(www.doxygen.org)등이 있단다.
장점
* 코드의 문서화와 업데이트를 촉진
* 컴파일할 수 있는 코드를 위해 별도의 단계가 필요하지 않다(문학적 프로그래밍과의 차이)
* 비교적 자연스럽게 보인다.
* 문서화 툴은 풍부한 검색, 상호 참조, 코드 아웃라인 기능을 지원
단점
* API의 문서화에만 정말로 유용하고, 내부 코드의 문서화에는 일반 코멘트를 사용해야 함
* 소스 파일을 훑어보고 개략적인 내용을 파악하기 어렵다.(이런 건 문학적 프로그래밍이 한 수 위)
주의
* public 항목에 대해서는 하나 또는 두 개의 문장으로 구성된 설명을 작성하라. 쓸데없이 주절주절 늘어놓지 말란 말이다.
* 변수나 파라미터가 어디에 사용되는지 분명하지 않으면 문서화하라. 단 이름만 보아도 확실하게 알수 있으면 문서화하지 마라.
*함수 파라미터 중 어떤 것은 입력에 사용되고 어떤 것은 출력에 사용된다면, 그런 사실을 파라미터 설명에 명확히 기술하라
* 함수의 전제조건, 후행조건, 발생할 수 있는 exception, side effect를 모두 문서화 하라.

생각해보니 2학년 때 이현아교수님이 문서화 툴에 대해 언급했었고 임은기 교수님도 권장한 적이 있다. 다만 귀찮아서 사용하지 않았다. 잠시 알아본 적도 있었지만 귀찮아서 사용하지 않았다. 문서화 툴은 형식이 일정한 것이 아니라 툴 마다 다르기 때문에 필요하다면 실무에서 사용되는 공통된 것을 이용하면 될 것 같다. 사용법이 그리 어렵지 않으니 그때그때 필요한 것을 배우면서 사용할 수 있다. 문서화 툴에 의존하기보다는 필요한 정보는 코멘트로 달아두는 습관을 기르는 것이 더 도움이 될 것 같다.

+ 파일에는 헤더를 유지 (파일명, 목적, 저작권 [, 특이사항])
+ 함수에도 헤더를 유지 (parameter, return value, 목적)
+ 변수는 이름만으로 명확한 것이 아니면 반드시 설명(객체형식이라면 이름이 확실해도 설명을 붙여두는 것이 좋다.)

728x90
728x90

의미있는 이름을 사용하라.
변수, 타입, 파일, 함수등 모든 것들의 이름은 의미가 있는 것이어야 한다. x,y,z,a,b,c같은 이름들은 나중에 자신이 봐도 정확히 이해하기 어려울지도 모른다.

함수 작성 시 유의
- 하나의 함수는 하나의 동작! (동사로 이름짓는 것이 원칙)
- side effect를 최소화하라(side effect란 함수가 실행되는 도중에 외부에 있는 값이나 상태를 바꾸는 것을 말한다.)
-  짧게 만들라. 한 화면에 모두 들어갈 수 있도록 하되 코드를 짧게 만들기위해 무리하게 줄이지는 마라.

제약을 많이 가하라.
- const등을 이용해서 값이 바뀌면 안되는 것들은 모두 상수화해라.
- 양수만 가진다면 unsigned type을 사용하라. 귀찮다고 그냥 넘기는 경우가 많다.
- 몇가지 선택사항이 있다면 열거형식(enum)을 활용하라.
(가끔 생각하는데 boxing과 unboxing에 대한 것, 혹은 casting에 관한 것이 이러한 제약들과 겹칠 경우 어떻게 해야 하는가..하는 문제다. unsigned type의 변수를 선언했는데 signed형식을 parameter로 사용하는 method를 이용해야 할 경우 강제형변환(type casting)이 필요하다. 이러한 형 변환이 많이 사용될 때는 그냥 처음부터 signed로 하는게 좋지 않을까?)

마법의 수를 피하라.
코드내에 숫자가 들어가는 경우를 magic number라고 한다. if(counter == 76)과 같은 코드를 만나게 되면 76이 무엇을 뜻하는지 모르게 된다. #define과 같은 코드를 사용해서 문자상수를 사용할 수도 있고 상수를 선언해서 사용할수도 있다.
더욱 심한 경우를 초보자들이 많이 사용하는데 문자를 구분할 때 숫자를 적어버리는 경우가 있다. 이러한 경우는 C언어에 한해서 많이 나타나는 상황인데 특정한 문자인지 확인하기 위해 그 문자의 ASCII코드값을 적어버리는 경우가 있다. source를 유니코드를 사용하는 언어에 그대로 사용할 경우가 생길지도 모른다. 코드값이 다른 상황이 생길지도 모른다. 문자와 상수가 비교되지 않는 컴파일러를 만날지도 모른다.
코드에 숫자를 직접 넣어버리는 것은 피하도록 하자.

연관된 정보는 묶어라.
프로젝트의 크기가 커질수록, 코드의 길이가 길어질수록, 함수와 클레스가 많아질수록 분류의 중요성은 더욱 강조된다. 큰 물에서 놀고싶으면 애초에 큰 물에서 하는 습관을 들여놔야 한다.
- 한 콤포넌트를 위한 API는 한 파일안에 표현해야 한다.
- namespace나 package등을 이용하여 그룹화하라. 관계가 있는 상수들은 enum으로 정의하라.

728x90
728x90
외부 문서의 지원이 필요한 코드는 작성하지 마라. 그런 코드는 취약하다. 코드 자체만으로 명료하게 읽히도록 만들어야 한다.
 - 외부 문서가 필요한 코드의 경우 수정 될 때마다 외부 문서를 같이 수정해야 한다. 처음 작성되었을 때 어떻게 되었는지 알 필요가 있는 경우 이러한 문서 작업은 더욱 복잡해 질 것이다. 큰 프로젝트를 작업하는데 이렇게 진행하면 힘들어서 제대로 진행하질 못한다.
 - 그렇다고 지나치게 상세한 코멘트(주석)로 코드 자체의 내용을 가리는 것도 옳지 않다. 코드만 보고도 쉽게 알 수 있는 곳이라면 코멘트를 자제하자. 어차피 코드만 보고 이해하기 쉽도록 만드는 것이 목표이니 코멘트는 필요없는 것인가? 코멘트가 필요한 곳과 작성요령은 나중에 다시 다룬다.

코드가 명료해지면 실수할 가능성이 적어지기 때문에, 코드의 품질이 높아지고, 유지보수 비용이 줄어든다. (가독성을 높이는 것이 최대 목표라고 생각해라.)

가끔 자신이 만든 소스를 다른 사람들이 쉽게 알아보지 못하는 것에 대해 쾌감을 느끼는 변태들이 있다. 단점은 그런 변태들과 같이 일하고 싶어하는 사람이 적다는 것이다.

같은 일을 하는 함수다. 어떻게 보이는지 감상해보자.

중요한 것은 짧은 코드를 작성하는 것이 아니라 다른 프로그래머가 봤을 때 쉽게 읽을 수 있고 명확한 코드를 작성하는 것이다.

if문의 함정에 조심하라!
 - 이건 책에서 강조하는 것이 아니라 내가 강조하는 내용이다. 책에서는 if-then-else 구조를 작성할 때 "정상"인 경우가 "에러"인 경우보다 항상 앞에 나오거나 그 반대가 되도록 하라고 권한다.

내가 권하는 방법은 if문은 가능한 처음부터 사용하지 말라는 것이다. 초보 프로그래머가 쉽게 작성하는 코드는 많은 문제를 if, else문으로 처리하려고 들고 if문 내에 전체 코드를 다 넣으려고 한다. 특히나 if문으로 오류처리를 하면서 전체 코드를 다 집어넣는 경우 처리할 오류가 많아질수록 중첩수준이 깊어진다.

그래서 일단 이론적으로 올바른 입력이 있을때(아무런 오류처리도 필요없을 때)의 코드를 먼저 작성하고 오류처리는 if문으로 나중에 추가하라고 권한다. 불필요한 경우 else문도 절대 사용하지 말것을 권한다. 이것이 올바른 것인지는 모르겠지만 중첩의 깊이가 적을수록 코드를 읽을 때 생각할 것이 줄어든다는 믿음에는 변함이 없다.
728x90
728x90
변수 :
- 명사로 이름 짓는다. ( 변수는 data 자체를 가리키는 경우가 많다.)

- 명사로 사용할 수 없을 땐 명사화된 동사를 사용(ex: count)

- 변수이름의 첫글자는 영문 소문자로 시작

※ 헝가리언 노테이션 : type에 관한 정보를 이름에 포함시키는 방식으로 멤버변수의 경우 m_으로 시작하고, 포인터의 경우 이름 뒤에 _ptr... 뭐 이런 식의 작명법을 말한다. 이 책에서는 그러한 방법을 따르지 말라고 경고하고 있다. Win32와 MFC의 라이브러리에서 헝가리언 노테이션을 따르는 것이 대중적인 사용의 주된 이유지만 type에 관한 정보는 선언할 때 보는 것으로 충분하며 그러한 것들을 표시해줘야 할 정도라면 함수의 크기가 너무 커서 불편하다는 것이므로 나누라고 권한다.
단, type정보가 아니라 기능에 대한 정보라면 이름에 포함하는 것이 맞다. (index기능을 하는 변수를 idx_로 시작하기도 한다.)

※ 머리글자 조합 : 각 단어의 머리글자를 따서 이름짓는 방식이다. (예를 들어 SomeTypeWithMeaningfulNaming 라는 이름이 있다면 stwmn으로 줄이는 것이다. 일반적으로는 사전에 나오는 내용으로 구성하는 것이 원칙이다. 하지만 변수가 좁은 범위에서 사용된다면 너무 긴 이름 대신 짧은 이름으로 대치하고 주석을 달아두는 것도 좋다.


함수:
- 동사로 이름 짓는다.

- be, do, perform등과 같은 의미없는 동사의 사용은 피하라.

- 주의 : 사용자의 입장에서 생각하라
. 초보자들이 흔히 하는 실수로 함수의 입장에서 이름을 짓는 것이다. 항상 함수를 사용하는 사용자 입장에서 이름을 지어야 한다.  어떻게 해야할지 모르겠다면 왜 이 함수를 만드는지 생각해보자. 적절한 예시가 떠오르지 않는다. 이건 자꾸 연습하다 보면 저절로 될 것이다.

- 주의 : 함수의 내부적인 구현 방법은 생각하지 말고 그 함수의 역할을 생각하라. 함수는 하나의 기능만 가지고 있고 그 기능이 무엇인지에 대해서 이름을 짓는 것이다. 기능을 구현하기 위해 어떤 일을 하건 상관하지 마라. 사과가 몇개인지 알기 위해 사용하는 함수라고 하자. 그럴때 보통 int countApples(); 이런 식의 이름을 지을 것이다. 그러면 사과가 몇개인지만 알면 됐지 이 함수가 재귀호출을 하건 file을 건들건 쓰레드를 만들건 신경쓰지 말라는 말이다.

타입(클레스):
- 클레스 이름은 객체가 아니라 클레스를 묘사해야 한다.(사소하지만 중요한 차이: '사람'이란 클레스 이름대신 '홍길동'이란 클레스 이름을 사용한다면?)

- 상태 값을 가지는 객체를 묘사한다면 명사.

- 함수객체(functor : 함수들 만으로 구성된 객체로 static으로 구현되는 경우가 많다.)거나 가상 call back interface를 구현하는 클레스는 동사 or 잘 알려진 디자인 패턴의 이름

- 클레스가 위의 두가지 성격을 모두 가진다면 이름 정하기가 어렵고, 잘못된 설계일 가능성이 크다.

- DataObject와 같이 당연한 내용을 포함하는 이름은 좋지 않다.(클레스는 data를 포함하는 경우가 많고, 객체화 한다면 당연히 object가 되는 것이 아닌가! 그러니 중복해서 언급할 필요가 없다.) : 좋지 않은 단어 -> class, data, object, type
 

namespace, package:

- 전체적인 내용을 봐라. 이건 꽤 큰 범위라 어휘력에 맡긴다.

- 불필요한 부가적 설명은 피하라 : UI, filesystem, controls등과 같은 이름은 다 좋은 이름들이다. controls_group와 같이 이미 알고있는 내용을 덧붙이지 마라. 길고 쓸데없는 내용은 보기 싫다.

매크로:
= 매크로는 위험하다. (단순 무식 과격하며 힘도 엄청나게 쎄다 : 소스코드가 컴파일 되기 전에 전처리 단계에서 매크로에 해당하는 내용은 모두 지정된 매크로를 거친 값으로 바껴버린다.) 아주 위험하므로 반드시 눈에 띄는 표시가 필요하다.(#define 문을 생각하면 쉽다.)

- 모두 대문자로 표기 (그래야 눈에 잘 띈다)

- 충분히 독특한 이름을 사용해야 한다.(독특한 파일이름이나 프로젝트 이름을 접두사로 붙이는 것이 도움이 될수도 있다. 절대 다른 곳에서 실수로 같은 이름이나 그 이름이 포함된 이름을 사용하면 안된다.)

파일:
- 대소문자에 주의하라. 파일검색은 대소문자 구분을 무시하지만 대소문자를 구분해서 사용하는 곳이 분명히 있다. 책에서는 파일이름을 모두 소문자로 하는 것도 좋은 방법이라고 소개하고 있지만 JAVA에서는 클레스와 인터페이스 이름에 PropreCase를 사용하며 이 이름과 파일 이름이 같아야 제대로 작동한다.

- 헤더파일과 헤퍼의 내용을 구현한 파일의 이름은 같도록 해라. stack.hstack.cpp와 같이 쌍을 이루란 말이다.

- 여러 언어를 혼용해서 사용할 경우 같은 이름에 확장자가 다른 것은 같은 디렉토리에 두지 마라. stack.c, stack.cpp, stack.java가 한 디렉토리에 들어있다면 stack.o파일은 뭘 나타내는 것일까? 자식은 하난데 아빠가 셋이다. 가정에 큰일이 날 수도 있다.

- 확장자를 신경써라. C++에서는 확장자를 .C  .cc  .cpp  .cxx  .c++등 여러가지가 있으며 특이하게 헤더파일의 확장자가 .h대신 .hpp로 쓰이는 경우도 있단다. 이런 마구잡이로 쓰인 확장자는 꽤 거슬리는데 MS의 노예가 된 우리는 .cpp와 .h로 거의 통일되어 있다.

대문자 사용의 관례

일관성을 유지하라
- 하나의 이름에 다양한 규칙을 적용하는 바보는 없을 것이다. Using_underscores_AndProperCase 이런거나 Another_Case 같은 이름은 사용하면 안된다는 말이다.

- 프로젝트 전체에 일관된 규칙을 적용해야 한다.
다음과 같은 코드는 일관성이 없어 제대로 분석되기 어려울 것을 예감할 수 있다.
콘텍스트 활용
※ 범위(scope)
- 이름의 범위는 global, namespace, class, function(method), loop등 다양하다. 범위에 따라 이름이 조금씩 바뀔 수도 있다는 것을 참고하자. 같은 변수라고 해도 함수내에 사용되느냐 전역이냐에 따라 이름이 다르게 사용되는 예가 가끔 있다.

※ 타입(type)
- 위에서 이미 말했지만 type을 이름에 넣지 말라는 것이 Code Craft란 책의 주장이다. string형식의 변수에 address_string이란 이름을 주어 재언급을 하는 것은 피하자는 것이다. 헝가리언 노테이션은 이런 재언급을 목적으로 하고 있기 때문에 종종 비웃음 산다고 한다.)
그러나
내가 생각하기에 이 책의 저자는 구식 사고방식을 가지고 있는 것 같다. JAVA나 C#등과 같이 다양한 콤포넌트들이 구현되어 있고 그것들을 따와서 사용하는 방식의 프로그래밍은 객체의 형식을 모두 기억하기 어렵다.
윈도우 응용 프로그램을 예로 든다면 form하나에 들어가는 구성요소(label, textbox, button등)의 종류가 많으면 이것들을 다 기억하기 어려울 수가 있다. 대체로 이러한 구성요소들은 form이 생성될 때 같이 생성되어서 form이 사라질 때까지 운명을 함께하기 때문에 scope가 너무 크다. 함수 내에서 사용되는 변수들은 type을 사용하는 것이 오히려 거추장스럽지만 범위가 넓은 경우 이름에 포함시켜 주는 것이 맞는 것 같다.(필요하니까 주장하는 사람들이 있는거다.) 다만 어떤 경우에 type을 적어주고 어떤 경우에 뺄 것인지 명확하게 구분지어 놔야 한다.
scope가 작은 경우 빼는 것이 좋고, 넓은 경우 넣는 것이 좋지만 프로젝트 전체에서 형식을 통일시켜야 일관성이 유지되니 심각하게 고민해봐야 할 사항이다.

(나의 경우엔 type을 적지 않는 편이다. 요즘은 tool들이 좋아서 이름만 있으면 어떤 형식인지 다 알려주기 때문에 그닥 필요하지가 않다. tool에 지배당하고 있는건가?)
728x90

+ Recent posts