2-5. Creating sample code

Google Technical Writing Course - 2

by 잡초

code라는 단어를 보자마자 약간 겁먹었는데, 결국 ‘좋은 샘플 코드를 작성하는 법’이었다. 모든 Technical Writing이 개발 분야에 국한된 건 아니겠지만...

백문이불여일견이라고, 어느 필드이건 ‘좋은 코드’ 역할을 하는 샘플이 있을 테니 그걸 잘 작성하고 활용하는 것이 중요할 것 같다.


목차는 아래 ‘좋은 샘플 작성법’을 하나씩 설명하는 식으로 구성되어 있다.


Good samples are correct and concise code that your readers can quickly understand and easily reuse with minimal side effects.




Correct


샘플 코드는 하기 기준을 만족해야 한다:


빌드 에러 없이 실행 가능할 것.

의도대로 동작.

최대한 실제 제품 수준에 가깝게 할 것. 예를 들어 보안 취약점 등이 포함되지 않도록 할 것.

해당 언어의 convention (스타일 가이드)를 따를 것.


또한 샘플 코드와 관련된 몇 가지 주의사항을 함께 다루고 있다.


샘플 코드는 팀 내에서 가장 best라고 합의한 방식으로 작성할 것.

샘플 코드도 꾸준한 검증 및 유지보수가 필요함.

유닛 테스트 코드를 샘플 코드로 재사용하지 말 것.

-> 유닛 테스트 코드는 개발 과정에서 기능 동작을 테스트하는 코드이기 때문에, 독자의 이해를 위해 작성되는 샘플 코드와는 그 목적이 다르다. 단순히 동작이 검증된 코드라고 그대로 문서에 가져다 쓸 경우, 개발 당사자들 위주로 작성된 간결한 코드를 외부 사용자는 이해하기 어려울 수밖에 없다.

스니펫을 과다하게 사용하지 말 것.

-> 스니펫(snippets)이란 샘플 코드의 일부분으로, 한 줄 ~ 몇 줄 정도로 짧게 잘라낸 코드 조각이라고 보면 된다. 스니펫은 전체 샘플 코드처럼 엄격하게 주기적으로 검증되지 않기 때문에, 시간이 지날수록 해당 코드는 오류 발생 확률이 높아진다. 특히 스니펫만 가져다 붙여서 문서를 작성하는 것은 지양해야 한다.


즉 요약하면 아래와 같다:


샘플 코드는 단순히 동작하는 코드가 아니라, 가장 잘 쓰는 방식으로 명확하게 보여주는 이해 중심용 코드여야 하며, 유닛 테스트나 스니펫처럼 검증 중심 코드와 혼동해선 안 된다.



Running sample code


좋은 문서는 샘플 코드를 어떻게 실행해야 하는지 알려준다. 특히 해당 코드 동작을 위해 요구되는 조건이나 사전 세팅이 있다면 함께 알려줘야 한다.

예로는 라이브러리 설치나 환경변수, IDE 설정 등이 있다.


다만 이렇게 알려줘도 독자가 꼭 그대로 따르란 법은 없다. 누군가는 사전 준비 없이 바로 코드를 실행하기를 원할 수도 있고, 나 같은 초심자들은 가이드를 잘못 이해하고 의도와 다르게 셋팅할 수도 있다. 그런 경우를 대비하여 문서 내에서 직접 실행 가능한 샘플 코드를 포함시키는 것도 좋다.


또한 샘플 코드가 난해한 경우, 예상 출력값을 함께 제시해주는 것도 좋다.



Concise


코드는 최대한 필요한 부분만 간결하게 제공할 것.

예를 들어 malloc 함수를 호출하는 법에 대해서라면, snippet 정도로 충분하지, 리눅스 소스 트리 전체 (운영체제 전체 구조, 수백만 줄)를 알려줄 필요는 없다.

다만 간결성(Conciseness)이 앞서 다룬 정확성(Correctness) 보다 우선순위가 되면 안된다. 내용을 명확하게 전달하는 것이 가장 중요하다.



Understandable


이해하기 쉬운 코드 작성을 위해 하기 항목들을 제안한다.


클래스, 함수, 변수 이름은 어떤 역할을 하는지 한 눈에 알 수 있게 짓는다.

불필요하게 어렵거나 까다로운 코드는 피한다.

너무 깊은 중첩 코드는 피한다. (for, if문 등)

필요시 볼드체나 색상 강조를 할 수 있으나, 과하게 사용하지 않도록 한다.



Commented


주석에 대한 내용.

기본적인 고려사항들은 하기와 같다:


주석은 간결하게 작성하되, 명확성을 우선시할 것.

당연한 내용을 일일히 주석으로 달 필요는 없지만, 그 전에 과연 ‘당연한 내용‘이 맞을지 고민해볼 것. (작성자는 전문가지만, 독자는 초심자일 수 있다.)

직관적이지 않은 부분에 주석을 추가할 것.

타겟 독자가 해당 주제에 익숙하다면, 코드가 ‘무엇을 하는지’보다는 ‘왜 이렇게 작성되었는지’에 초점을 맞출 것.


주석을 코드 안에 함께 작성할 것인지, 아니면 코드 밖에 따로 작성할 것인지에 대해서는 하기 가이드라인을 따른다.


샘플 코드를 복사해서 가져갈 때는 주석도 함께 복사되기 때문에, 최종 포함되어야 하는 주석이라면 코드 안에 함께 작성한다.

반면, 길고 복잡한 개념 설명이 필요한 경우라면 샘플 코드 밖에 별도로 설명하는 것이 효과적이다.


참고로 샘플 코드의 이해도와 간결성을 위해 실제 제품 수준에서 포함되어야 하는 내용들(예외처리, 보안, 인증 등)이 빠지는 경우, 그 부분에 대해서도 주석을 남기도록 하자. 예를 들면 하기와 같다.


# 단순화를 위해 인증 및 오류 처리는 생략했습니다.

# 실제 서비스에서는 인증 토큰 확인 및 예외 처리를 추가해야 합니다.


Exercise


하기 주석의 문제점 파악하기.


/* Create a stream from the text file at pathname /tmp/myfile. */
mystream = br.openstream(pathname="/tmp/myfile", mode="z")


모범답안에 따르면 아래와 같다.


1. 주석이 쓸데없이 자세하다.

-> at pathname /tmp/myfile.라는 주석은 이미 코드에 pathname="/tmp/myfile"라고 나와있다.


2. 모호한 부분에 대해서는 설명이 없다.

-> mode는 무엇이고 그 값인 z는 무엇인지? 즉 직관적으로 알 수 없는 부분(non-intuitive)에 대해서는 설명이 없다.


챗GPT한테 주석 수정본 작성을 요청해보았고, 하기와 같은 답을 받았다.


# 압축된 텍스트 파일을 열기 위해 압축 모드("z")를 사용합니다.




Reusable


샘플 코드가 어느 환경에서든 유연하게 사용 가능하도록 작성하라는 것으로, 조금 더 구체적으로는 아래와 같다.


샘플 코드 실행에 필요한 모든 정보 (의존성, 환경 설정 등)를 제공할 것.

확장하거나 커스터마이징에 용이한 구조로 작성.


추가로, 샘플 코드가 이해 목적으로 깔끔하게 작성되어 잘 실행되는 것도 중요하지만, 다른 앱이나 프로젝트에 그대로 사용할 경우 잠재적인 부작용이 없을지에 대해서도 고려가 필요하다.


이 부분이 이해가 잘 되지 않아서 찾아봤는데, 실제로 샘플 코드를 그대로 복붙해서 실제 제품이나 서비스에 사용하는 경우도 종종 있다고 한다 (특히 초보자나 신입). 그런 경우를 대비해서 기본적인 에러 처리나 보안, 그리고 성능적인 측면도 고려를 하라는 뜻이었다.


ex) 작은 규모의 테스트에서는 괜찮지만 규모가 커질수록 CPU 연산과 메모리 사용랑이 급증하는 코드.




The example and the anti-example


좋은 예시 뿐만 아니라 반례도 함께 작성하면 독자의 이해를 도울 수 있다는 이야기.

예시는 아래와 같다.


* Good example

# A valid string assignment.
s="The rain in Maine."


* Anti-example

# An invalid string assignment because of the white space on either side of the
# equals sign.
s = "The rain in Maine."




Sequenced


쉬운 과정부터 점점 심화 학습까지, 난이도에 따라 단계적으로 구성하라는 뜻이다.

대표적으로 많은 가이드 문서에서 등장하는 “Hello world program​"이 있는데, 샘플 코드를 소개하는 가장 기본적인 예제라고 볼 수 있다.


그러한 단순한 예제로 시작하여 독자가 중간 ~ 복잡한 예제까지 순서대로 받아들일 수 있도록 문서를 작성하자.


아래 Exercise에서 순차 구성에 대한 Good/Bad 예시를 확인할 수 있다.


Exercise


아래 예제 중 Good/Bad를 구분해보기.

참고로 예상 독자는 해당 분야에 문외한이고, 이 문서는 함수의 개념에 대해 소개하는 문서이다.


하기 3가지 경우 중 좋은 예시는 1번이고, 2/3번은 각각 보완이 필요하다.


1. The following set of functions:

A function that takes no parameters and doesn't return anything.

A function that takes one parameter but doesn't return anything.

A function that takes one parameter and returns one value.

A function that takes three parameters and returns one value.


단순히 사례를 나열한 것 같지만, 사실 함수의 구조 자체부터 시작해서 입력값/출력값의 개념을 하나씩 추가해나가는 구성으로 짜여져있다.

즉 입문자가 가장 기초부터 시작해 난이도별로 차근차근 받아들이기 적합한 함수 소개 예시이다. 자세히는 아래와 같다.


1) 파라미터 없음, 반환 없음 -> 함수의 기본 구조 이해.

2) 파라미터 1개, 반환 없음 -> 입력값 처리 개념 도입.

3) 파라미터 1개, 반환 있음 -> 반환값 개념 도입, ‘입력 - 처리 - 출력’ 흐름까지 완성.

4) 파라미터 3개, 반환 있음 -> 복수 인자 다루기 및 함수에 대한 개념 완성.



2. The following set of functions:

A function that takes three parameters and returns one value.


1번의 4)에 해당하는 부분으로, 처음부터 너무 복잡한 구조이다. 문제에는 타이틀만 나열되어 있어서 간과할 수도 있지만, 실제 코드 예시가 들어가면 얼마나 길어질지 생각해보면 이해가 쉽다.


3. The following set of functions:

A function that takes one parameter and returns one value.

A function that takes three parameters and returns one value.


듬성듬성한 미완성 예제. 흐름도 없고, 딱 봐도 아웃.



사실 얼핏 봐서 이해가 되지 않았다. 1번이 가장 구체적이라는 건 알겠는데, ‘난이도에 따른 순차적 진행’이라는 관점에서 봤을 때 그저 평등한 수준의 항목들을 단순히 나열한 것처럼 보였기 때문이다.


하지만 위에 기술한 것처럼 전체 완성본이 어떻게 나올지 상상해보면, 1번처럼 step by step으로 가지 않고 2번의 최종 예시부터 딱 등장했을 때 어떨지 쉽게 감이 잡힌다. 당장 눈에 들어오지도 않을 것이다.



어쨌든 이해가 잘 되지 않아서 챗gpt에게 설명을 요청한 부분이고, 여러모로 Course1보다 Course2에서는 챗gpt의 도움을 많이 받았다.


여기까지 해서 pre-class는 끝났고, 이 다음은 in-class이다.

잘 부탁한다, 챗gpt.




출처 : https://developers.google.com/tech-writing/two/sample-code#correct





keyword
매거진의 이전글2-4. Illustrating