View
3.930
Download
2
Category
Preview:
Citation preview
Programming Skills - 1Coding Convention
Commenting Guide / Tools
JiHyung Lee / miksystem, Inc
jhlee@miksystem.com
목차
Coding Convention
• 코딩 컨벤션이란?
• 코딩 컨벤션의 요소- 주석, 네이밍, 코드 작성 규칙
• 언어 별 코딩 컨벤션- C/C++, Java, C#, Javascript …
• 코딩 컨벤션에 도움이 되는 IDE 확장 툴
- Visual Studio
목차
Commenting Guide / Tools
• 주석(Comment)의 필요성
• 잘 짜여진 코드는 문서가 필요 없다?
• 주석을 작성하는 대표적인 방법들(C#)- 소스 파일, 클래스, 메소드 …
• 언어 별 코멘팅 가이드- C/C++, Java, Javascript …
• 코멘팅에 도움이 되는 IDE 확장 툴
• 코드 문서화 도구
코딩 컨벤션이란?
• 코드를 작성하는 여러 규칙
• 들여쓰기(Indentation) 방법 → Tab 또는 Space(2, 4) ?
• 라인 당 최대 가이드 라인의 기준(80, 100)
• 중괄호(Brace) 사용 기준
• Namespace, Class, Method, Variable … 등의 명명 규칙
• 소스 코드 파일 이름 작성법
• 주석 작성 규칙
코딩 컨벤션이 필요한 이유
• 일관된 규칙 없이 작성된 코드는 같은 프로젝트 멤버라도 빠른 시간 안에
파악하기 힘듬. 이는 생산성과 업무 효율에 영향을 미칠 수 있다.
PdfEngine.cs
BaseEngine.cs
XpsEngine.cs……………………………….……………………………….……………………………….……………………………….……………………………….……………………………….……………………………….
코딩 컨벤션이 필요한 이유
• 컨벤션 내에서 작성된 코드는 개발자가 다른 부분을 신경 쓸 필요 없이
비즈니스 구현에 좀 더 집중 할 수 있게끔 도와 준다.
• 내가 작성한 코드는 아니지만 파악하기가 수월하다. (가독성 ↑ ↑ )
• 파악하기가 수월해지므로 유지 보수의 비용이 절감된다.
• 코드의 품질이 높아진다.
코딩 컨벤션이 잘 적용된 예제
Chromium Project
- 구글의 웹브라우저 오픈소스 프로젝트
- 프로젝트 커미터의 수 : 22명 (공식 리스트 기준. 더 있을지도…?)
- 크롬은 크로미움을 바탕으로 개발되는 Google Product.
Flash Plugin
AV Codec
Other Libraries …
코딩 컨벤션이 잘 적용된 예제
#include "base/guid.h"
#include "base/rand_util.h"#include "base/stringprintf.h"
namespace base {
bool IsValidGUID(const std::string& guid) {const size_t kGUIDLength = 36U;if (guid.length() != kGUIDLength)
return false;
std::string hexchars = "0123456789ABCDEF";for (uint32 i = 0; i < guid.length(); ++i) {char current = guid[i];if (i == 8 || i == 13 || i == 18 || i == 23) {
if (current != ‘-')return false;
} else {if (hexchars.find(current) == std::string::npos)return false;
}}return true;
}
} // namespace base
• Tab 대신 Space를 2칸씩 사용한다.
• 다른 header 파일을 참조 할 경우,root부터 header 파일까지의 경로를 모두 적는다.
• namespace 내부 선언은 들여쓰기를 하지 않는다.
• namespace가 끝나는 부분은// namespace “name” 을 명시한다.
• Function은 대문자로 시작하며 언더바를사용하지 않는다.
• 상수는 k로 시작한다. (kGUIDLength)
• 가이드 라인은 최대 80 컬럼으로 제한한다.
#include "base/task_runner.h“#include "base/compiler_specific.h“#include "base/logging.h“#include "base/threading/post_task_and_reply_impl.h"
namespace base {namespace {
// TODO(akalin): There's only one other implementation of// PostTaskAndReplyImpl in WorkerPool. Investigate whether it'll be// possible to merge the two.
class PostTaskAndReplyTaskRunner : public internal::PostTaskAndReplyImpl{public:explicit PostTaskAndReplyTaskRunner(TaskRunner* destination);
private:virtual bool PostTask(const tracked_objects::Location& from_here,
const Closure& task) OVERRIDE;
// Non-owning.TaskRunner* destination_;
};
PostTaskAndReplyTaskRunner::PostTaskAndReplyTaskRunner(TaskRunner* destination) : destination_(destination) {
DCHECK(destination_);}
bool PostTaskAndReplyTaskRunner::PostTask(const tracked_objects::Location& from_here,const Closure& task) {
return destination_->PostTask(from_here, task);}
} // namespace} // namespace base
#include "base/sys_info.h“
#include <windows.h>#include "base/files/file_path.h“#include "base/logging.h“#include "base/memory/scoped_ptr.h“#include "base/stringprintf.h“#include "base/threading/thread_restrictions.h“#include "base/win/windows_version.h“
namespace {
int64 AmountOfMemory(DWORDLONG MEMORYSTATUSEX::* memory_field) {MEMORYSTATUSEX memory_info;memory_info.dwLength = sizeof(memory_info);if (!GlobalMemoryStatusEx(&memory_info)) {
NOTREACHED();return 0;
}
int64 rv = static_cast<int64>(memory_info.*memory_field);if (rv < 0)
rv = kint64max;return rv;
}
} // namespace
코딩 컨벤션의 구성 요소
들여쓰기(Indentation)
네이밍 규칙
클래스, 메소드, 변수
(static, member, local)
중괄호(Brace)
주석(Comment)
소스 코드파일 분류 및네이밍 규칙
코딩 컨벤션의 구성 요소
• 들여쓰기(Indentation)
- 코드의 가독성을 높이기 위해 왼쪽 첫번째 컬럼부터 오른쪽으로 일정한 간격을띄워 쓰는 방법
- Tab 또는 Space를 사용하는데, 일반적으로 Space 사용을 권장.Tab은 에디터마다 간격이 다르기 때문에 대부분의 에디터에서 동일하게 표현하고싶다면 Space를 사용해야 함. (일반적으론 4칸을 사용)
- 최신 IDE는 대부분 Tab → Space으로 자동변환 기능을 제공.
코딩 컨벤션의 구성 요소
• 들여쓰기(Indentation)
- 매개변수가 많은 메소드일 경우 아래와 같이 좌측 정렬을 권장.
public static void AddRecipientsToOutlook(Outlook.MailItem mailItem,Outlook.Recipients recipients,Outlook.OlMailRecipientType type,bool clear = true)
{// …
}
코딩 컨벤션의 구성 요소
• 들여쓰기 스타일의 종류 [link]
static char*concact (char *s1, char *s2){while (true){something();
}finalthing();
}
GNU 스타일
static char*concact (char *s1, char *s2){
while (true) {something();
}finalthing();
}
K & R 스타일
static char*concact (char *s1, char *s2){
while (true) {
something();}finalthing();
}
BSD 스타일
코딩 컨벤션의 구성 요소
• 네이밍 규칙(Naming Convention)
- 클래스, 함수, 변수 등의 이름을 작성하는 규칙으로, 이해하기 쉬운 이름으로 작성해야개발자가 소스 코드 구조를 쉽게 알 수 있다.
- 이름을 축약하기 보단 길어도 좋으니 명확하게 작성하는 것이 좋다.다만, 아래와 같이 너무 길면 곤란할지도...
Java – com.java.swing.plaf.nimbus packageInternalFrameInternalFrameTitlePaneInternalFrameTitlePaneMaximizeButtonWindowNotFocusedState
Objective C – NSBitmapImageRep- (id)initWithBitmapDataPlanes:(unsigned char **)planes
pixelsWide:(NSInteger)width pixelsHigh:(NSInteger)height bitsPerSample:(NSInteger)bps samplesPerPixel:(NSInteger)spp
hasAlpha:(BOOL)alpha isPlanar:(BOOL)isPlanarcolorSpaceName:(NSString *)colorSpaceName
bitmapFormat:(NSBitmapFormat)bitmapFormatbytesPerRow:(NSInteger)rowBytes
bitsPerPixel:(NSInteger)pixelBits;
코딩 컨벤션의 구성 요소
• 네이밍 규칙(Naming Convention)
- 네이밍 규칙은 일반적으로 선립되어 있는 규칙들이 많이 사용 됨.특정 언어(+ 컴파일러) 개발사가 가이드를 제시하는 경우도 많음.
분류 특징(예제) 사용되는 언어 및 플랫폼
Pascal Case BackColor, IsConnected C++(VC), .NET(c, m, p), Java(c)
Camel Case backColor, isConnected Java(m), Javascript(f)
Upper Case System.IO .NET
Snake Case hello_world(), get_name() C/C++, Ruby
Hungarian notation szName, arrNumberList, bReadLine, g_nWheel C/C++(VC, MFC)
@EReceiverpublic class PackageBroadcastReceiverServiceImpl extends AbstractBroadcastReceiver
implements Service {
private final Logger logger = Logger.getLogger(PackageBroadcastReceiver.class);
@Prefprotected Preferences mPrefs;
@Overridepublic void onReceive(Context ctx, Intent it) {
String action = it.getAction();
if (action == null)return;
switch (action) {case Intent.ACTION_PACKAGE_ADDED: {
// …}break;
case Intent.ACTION_PACKAGE_FULLY_REMOVED: {// …
}break;
}}
@Overrideprotected void onServiceConnected(Context ctx) {
// …}
}
일반적인 Java 코드
• Class는 Pascal Case를 사용.Interface를 구현했다면“클래스명 + 인터페이스명 + Impl”.
• 추상 클래스는 클래스 앞에Abstract를 표기.
• 상수는 대문자 언더바(‘_’)를 사용.
• 멤버 변수는 “mName“ 또는 “m_Name”, “_name” 등으로 prefix를 붙여로컬 변수와 구분이 가능하게 작성.
• 메소드는 Camel Case를 사용
• 조건문(if)의 내부 코드가 1줄로 끝나면중괄호(Brace)를 사용하지 않음.
• Indentation은 2 or 4칸
일반적인 C# 코드
• Class는 Pascal Case를 사용.추상 클래스도 동일하게 표기.
• 인터페이스의 prefix는 I를 사용.
• 멤버 변수의 경우 동일한 프로퍼티가있다면 Camel Case로 작성. 또는언더바(_) prefix를 붙이기도 함.
• 메소드는 Pascal Case를 사용.
• 조건문(if)의 내부 코드의 길이와 상관없이 Brace로 블록 처리.
• Java 진영과 달리, Brace는 항상new line으로 시작.
• Indentation은 대부분 4칸을 사용.
namespace Test{
public abstract class BaseClass{
public abstract string Name { get; set; }}
public class DerivedClass : BaseClass, IDisposable{
private bool disposed = false;private string name;
public void Dispose(){
Dispose(true);GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing){
if (disposed){
return;}
if (disposing){
//}disposed = true;
}
public override string Name{
get { return name; }set { name = value; }
}}
}
코딩 컨벤션의 구성 요소
• 소스 코드 파일 분류 및 네이밍 규칙
- “디렉토리/소스파일” 구조를 권장. 디렉토리 구분은 코드의 기능 & 성격별로 묶는다.
- .NET에선 디렉토리가 namespace 최소 단위를, Java에선 package를 의미한다.
- C/C++은 디렉토리와 매칭되는 단위 개념은 없으나, .NET, Java와 같이 구성하는 것은
어렵지 않으므로 동일한 방식을 권장함.
- 소스 파일명은 .NET, Java의 경우 Pascal Case를, C/C++은 Snake/Pascal Case를 사용.
Useful Coding Style Guides
• Google- C++ Style Guide [link]- Java Style Guide [link]- JavaScript Style Guide [link]
- Python Style Guide [link]
• Microsoft- C# Coding Standard [link]- C# Object Naming Convention [link] - C/C++ Coding Convention [link]
• Apple- Objective-C Conventions [link]
• A Style [Visual Studio / link]
- C/C++, C# Code Formatter를 파일로 관리 가능. (공유 차원에서 편리함)
- TOOLS → Options → AStyle Formatter
• Indent Guides [Visual Studio / link]
- 코드의 Indent Line을 선으로 표시해, 라인 별 Indentation을 눈으로 쉽게구분 할 수 있음.
• Editor Guidelines [Visual Studio / link]
- Text Editor에 Guide Line을 그려줌. (스크린샷의 우측 세로 줄)
- 보통 80 또는 100 컬럼을 기준으로 사용하며 해당 라인을 넘기지 않도록코드를 작성.
주석(Comment)의 필요성
• 코드만으론 모든 것을 전달 할 순 없다.
• 코드 & 비즈니스 로직에 대한 개략적 설명을 제공하기 위해 사용.
• 코드 수정 이력을 남기기 위해 사용.
• 오픈소스의 경우, 소스 파일 최상단에 라이선스에 대한 설명을 넣기도 함.
/// @brief 파라메터에 해당하는 캐시가 존재하는지 검사한다./// @param dm : 디스플레이 모델/// @param pageNo : 페이지 번호/// @param rotation : 회전 각도/// @param zoom : 배율/// @param pTile : 타일/// @return true : 타일에 해당하는 캐쉬가 존재./// @return false : 존재하지 않음.bool Renderer::ExistsCache(const DisplayModel &dm, int pageNo, int rotation, float zoom, const TilePosition *pTile) {auto pCache = FindCache(dm, pageNo, rotation, zoom, pTile);if (pCache)
DropCache(pCache);
return pCache != nullptr;}
/// @brief 캐시 리스트에서 해당 캐시를 삭제한다./// @param cache : 캐시 리스트에서 삭제 할 캐시.void Renderer::DropCache(BitmapCacheEntry *pCache) {ScopedCritSec scope(&m_CacheAccess);assert(pCache);
if (!pCache)return;
if (0 == --pCache->refs) {PDF_LOG(INFO) << "Drop the cache. [Page No : " << pCache->page_no << "]";delete pCache;
}}
/// @brief 캐시된 페이지를 해제한다./// @param pDm : DisplayModel/// @param pageNo : 페이지 번호/// @param pTile : Tile Positionvoid Renderer::FreeCachedPage(const DisplayModel *pDm, int pageNo, const TilePosition *pTile) {
- 의미 없는 많은 주석은 오히려 전체 코드에대한 가독성을 떨어뜨릴 수 있다.
- 함수/매개변수명만 잘 지어도 대부분의 주석은생략이 가능하다. (이런 경우 구현 로직에 대한간단한 설명만 붙여도 좋다. SI에선 불가능..)
- 좌측처럼 함수, 매개변수, 리턴값에 대한주석들은 기능 수정시 오히려 관리 포인트만가중시키는 결과를 낳는다. (중요한 부분이아닌데도..!)
- 주석 다느라 시간 다 보낸다. (개발은 언제?)
- 하지만 특정 Platform을 개발하고 API를제공 할 계획이라면, 함수 단위 주석은 필수다.
#include <stack>
#include "base/base_export.h"#include "base/basictypes.h"#include "base/callback.h"#include "base/synchronization/lock.h"
namespace base {
// This class provides a facility similar to the CRT atexit(), except that// we control when the callbacks are executed. Under Windows for a DLL they// happen at a really bad time and under the loader lock. This facility is// mostly used by base::Singleton.//// The usage is simple. Early in the main() or WinMain() scope create an// AtExitManager object on the stack:// int main(...) {// base::AtExitManager exit_manager;//// }// When the exit_manager object goes out of scope, all the registered// callbacks and singleton destructors will be called.class BASE_EXPORT AtExitManager {
...
};} // namespace base
at_exit.h
• Class에 대한 설명, 활용도 및사용 방법에 대한 안내 제공.
• AtExitManager는 Application 종료시Manager에 등록된 콜백 또는 Task를호출하여 마무리 작업을 할 수 있게끔 도와줌.
class BASE_EXPORT AtExitManager {public:typedef void (*AtExitCallbackType)(void*);
AtExitManager();
// The dtor calls all the registered callbacks. Do not try to register more// callbacks after this point.~AtExitManager();
// Registers the specified function to be called at exit. The prototype of// the callback function is void func(void*).static void RegisterCallback(AtExitCallbackType func, void* param);
// Registers the specified task to be called at exit.static void RegisterTask(base::Closure task);
// Calls the functions registered with RegisterCallback in LIFO order. It// is possible to register new callbacks after calling this function.static void ProcessCallbacksNow();
protected:// This constructor will allow this instance of AtExitManager to be created// even if one already exists. This should only be used for testing!// AtExitManagers are kept on a global stack, and it will be removed during// destruction. This allows you to shadow another AtExitManager.explicit AtExitManager(bool shadow);
private:base::Lock lock_;std::stack<base::Closure> stack_;AtExitManager* next_manager_;
// Stack of managers to allow shadowing.DISALLOW_COPY_AND_ASSIGN(AtExitManager);
};
• 함수에 대한 설명 및 주의 사항을제공.
• 함수/매개변수에 대한 교과서적인설명보단 구현 원리, 로직의 흐름에초점을 맞춘 주석을 제공.
• at_exit.h 에서 대부분의 설명이 제공되기 때문에 소스 파일에선특별히 주석을 제공하지 않는다.
• 또한 클래스와 함수명이 직관적이기때문에 눈으로도 쉽게 이해 할 수 있다.
• 잘 작성된 코드는 그 자체가 문서와같다.
AtExitManager::AtExitManager() : next_manager_(g_top_manager) {// If multiple modules instantiate AtExitManagers they'll end up living in this// module... they have to coexist.#if !defined(COMPONENT_BUILD)
DCHECK(!g_top_manager);#endif
g_top_manager = this;}
AtExitManager::~AtExitManager() {if (!g_top_manager) {NOTREACHED() << "Tried to ~AtExitManager without an AtExitManager";return;
}DCHECK_EQ(this, g_top_manager);ProcessCallbacksNow();g_top_manager = next_manager_;
}...void AtExitManager::RegisterTask(base::Closure task) {if (!g_top_manager) {NOTREACHED() << "Tried to RegisterCallback without an AtExitManager";return;
}AutoLock lock(g_top_manager->lock_);g_top_manager->stack_.push(task);
}
void AtExitManager::ProcessCallbacksNow() {if (!g_top_manager) {NOTREACHED() << "Tried to ProcessCallbacksNow without an AtExitManager";return;
}AutoLock lock(g_top_manager->lock_);while (!g_top_manager->stack_.empty()) {base::Closure task = g_top_manager->stack_.top();task.Run();g_top_manager->stack_.pop();
}}
at_exit.cc
Sandcastle Tool (.NET CHM Generator)
• MS에서 제공하는 MSDN 스타일
코드 문서화 툴
• 빌드된 DLL들을 대상으로
Reflection을 통해 문서를 생성.
• 프로젝트 빌드시 생성되는 XML
documentation file과 통합 가능.
• 문서 생성시 시간이 꽤 걸린다는단점이 있음. (.NET DLL을 포함 시킨 경우에만…)
• 참고 [link]
Sandcastle Tool (.NET CHM Generator)
• 주석은 좌측과 같이 작성.
• 코드 상단위에서 /// 를 입력하면
Summary가 자동 완성 됨.
namespace WindowsFormsApplication1 {
/// <summary>/// 테스트 폼/// </summary>public partial class Form1 : Form{
/// <summary>/// 생성자/// </summary>public Form1(){
InitializeComponent();}
/// <summary>/// 윈도우 캡션을 세팅한다./// </summary>/// <param name="title">캡션 타이틀</param>public void SetWindowText(string title){
Text = title;}
}}
Sandcastle Tool (CHM Generator)
1. Sandcastle tool 설치 [link]
2. Sandcastle Help File Builder 설치 [link]
3. C:\Program Files (x86)\EWSoftware\Sandcastle Help File Builder\SandcastleBuilderGUI.exe 실행
4. File -> New Project -> 프로젝트 이름으로 저장
5. Project Exploerer에서 Documentation Sources에 문서를 생성 할DLL과 Xml documentation file을 추가
6. Project Properties -> Help File에 CHM 문서에 대한 정보를 기입
7. “Ctrl + Shift + B”를 눌러 빌드를 시작.
Doxygen Wizard (C/C++, Java, C#, PHP CHM Generator)
• Java/C++(GNU) 진영에서 많이
사용하는 코드 문서화 툴.
• 코드 상단에 Doxygen format으로
작성된 주석을 파싱하여 생성.
• VS의 Code Tooltip 포맷으로
사용되는 Summary 포맷과 달라서
VS와의 궁합은 좋지 않음.
• 여러 언어를 지원하기 때문에,툴 또한 Cross Platform을 지원.
• CHM, HTML, PDF 등의 포맷 지원.
Doxygen Wizard (C/C++, Java, C#, PHP CHM Generator)
• 주석은 좌측과 같이 작성.
• Doxygen Add-In을 설치했다면 상단 툴바에
“Add Code Comment”라는 버튼이 추가됨.
주석을 작성하고자 하는 코드에 커서를 두고
버튼을 누르면 포맷이 추가 됨.
namespace WindowsFormsApplication1 {
/*!* \brief 테스트 폼*/
public partial class Form1 : Form{
/*!* \brief 생성자*/
public Form1(){
InitializeComponent();}
/*!* \brief 윈도우 캡션을 세팅한다.* \param title 타이틀 캡션*/
public void SetWindowText(string title){
Text = title;}
}}
Doxygen Wizard (C/C++, Java, C#, PHP CHM Generator)
1. Doxygen Wizard 설치 [link]
2. DoxyComment Add-In for VS 2013 설치 [link]
3. 설치가 완료되면 아래 경로의 파일을 다음과 편집.
경로: C:\Program Files (x86)\SourceForge.net\DoxyComment add-in for Visual Studio\DoxyComment.addin
편집내용: <HostApplication>
<Name>Microsoft Visual Studio</Name><Version>13.0</Version> <----- 이 부분을 12.0 으로 수정해야 vs2013에서 add-in 인식이 된다.
</HostApplication>
Javadoc (HTML, on IntelliJ, Eclipse)
• Java 플랫폼에서 많이 사용.
• 대부분의 IDE(Java)가 지원하는
Code Tooltip 포맷은 Javadoc이기
때문에 99% 사용한다고 볼 수 있음.
• 기본 output 포맷은 HTML을 지원
하며 커스텀 툴을 사용한다면
CHM 변환도 가능.
/*** <p>SearchDevice Presenter Implementation.</p>* @author JiHyung Lee(miksystem, Inc)* @since 2014.07.22*/
@EBeanpublic class SearchDevicePresenterImpl
extends AbstractBasePresenter<SearchDeviceView>implements SearchDevicePresenter, RemoteDeviceEventListener {
/** Remote Device Manager */@Beanprotected RemoteDeviceManager mDeviceManager;
/*** Constructor** @param ctx {@link
com.kt.android.silverpia.master.ui.activity.searchdevice.SearchDeviceView}를 상속 받은 컨텍스트 액티비티.
*/public SearchDevicePresenterImpl(Context ctx) { super((SearchDeviceView) ctx); }
• 주석은 좌측과 같이 작성.
• Doxygen 포맷과 유사.
• HTML 태그 포함 가능.
Javadoc (Java, HTML Document Generator)
Javadoc (on Eclipse)
• IntelliJ IDEA나 Eclipse에서 Javadoc
생성시 설정 가능한 옵션은 큰 차이가
없는데, 이는 JDK 설치 폴더 밑에 있는
javadoc.exe를 이용하여 문서를 생성하기
때문이다.
• IDE마다 생성되는 Javadoc의 테마가 다른
이유는 문서 생성시 IDE가 stylesheet.css를
덮어 씌우기 때문이다.
YUIDoc (Javascript, HTML Document Generator)
• Javascript 전용 코드 문서화 툴.
• Node.js 어플리케이션으로
배포 중
• npm이 설치되어 있다면 쉽게 사
용 가능.
• Node.js를 이용한 Server Mode를
지원하여, 실시간 API Reference
Page를 구성 할 수 있음.
1. Node.js 설치 [link]
2. CMD에서 “npm –g I yuidocjs” 실행 [link]
3. js 소스 최상위 루트 폴더로 이동 후 “yuidoc . –c <json.file>” 실행.아래와 같이 옵션 json 파일을 구성해서 argument로도 전달 가능.
// config.json{
"name": "The Foo API","description": "The Foo API: a library for doing X, Y, and Z","version": "1.2.1","url": "http://example.com/","options": {
"outdir": "../build/apidocs"}
}
YuiDoc (Javascript, HTML Document Generator)
Recommended