개발/학교 수업

[소개원실/swpp] Coding Style

Woogie2 2021. 10. 21. 18:41
반응형

Code Layout

개인 취향에 따라 다르다. 하지만 특정 규칙을 정해놓고, 통일성있게 작성하자.

Evidence that Layout Matters

  • Chase & Simon (1973): "Preception in Chess"
  • Schneiderman(1975): "Exploratory Experiments in Programmer Behavior"
  • McKeiten et al. (1981)
  • Soloway & Ehrlich (1984)

파이썬

  • 래이아웃은 일등 시민이다

원칙과 목표

  • 비주얼 레이아웃 -> 프로그램의 논리적 구조
    • 목표: 코드를 예쁘게 만드는 것이 아닌 이해하기 쉽게 만든다.
  • 다른 프로그래머들의 경험을 빌리자.
    • 더욱 빠르게 전문가가 될 수 있음
  • Withstand the test of time
    • how to maintan layout and commnets as code evolves
    • modifying one line shouldn't require changing many others

화이트 스페이스(공백 문자)

  • 공백 문자는 그룹화를 위한 기반을 제공.
  • 공백 문자는 문자를 이해하는데 아주 중요함.
  • 들여쓰기(indentation)는 논리적인 구조를 보여줌. (탭(들여쓰기)은 2~4개의 스페이스가 적당)

괄호

  • 계산 순서를 보여줌. 따라서 오해를 막을 수 있음

Code Layout (Classes)

클래스의 설계, 배치

  1. Header comment
  2. Class data
  3. Public methods
  4. Protected methods
  5. Private methods

Using Files

  • interface, implementations를 파일로 분리
  • 파일마다 하나의 클래스
  • 클래스 이름을 먼저 짓고, 파일 이름을 정하라.
    • 자바는 이런 방식 이미 사용중
    • 클래스 이름을 위해서는 upper camel case(= PascalCase)를 사용할 것.(e.g., UpperCamelCase)
  • 파일 내에서 메서드를 확실히 구별 가능하게 작성
    • 최소한 2개의 빈 라인을 둬서 구분

Python PEP8 Naming

  • 모듈 이름(파일 이름)은 short, all-lowercase이어야 하며, undercore(_)을 포함할 수 있다.
  • 패키지 이름(디렉토리명)은 모듈 이름 조건과 동일하지만 underscore를 포함할 수 없다.
  • 클래스는 CapWords 컨벤션을 따른다.
  • CapWord* : 각 글자의 첫 글자를 대문자로.

포맷팅(Formmating)

  • 코드 한 줄의 길이 <= 120개의 문자
    • 120은 사실 너무 많고 일반적으로 80개 이내로 할 것.
  • 클래스의 코드 줄 수 <= 2,000줄
    • 최대한 적게.

Code Layout(Methods)

일반적인 구조

  • 반환값 + 파라미터
  • 예외(Exceptions)
  • 여는 중괄호
  • 메서드 본문
  • 닫는 중괄호

파라미터

  • 파라미터를 적을 때, 적용되는 tab 간격을 동일하게, 이쁘게 만드려고 임의로 탭간격을 다르게 할 필요 X

간단한 메서드

  • 메서드를 작고 focused하게 유지
    • 50줄이 넘어가면 restructuring을 고민할 것
    • 150줄이 넘지 않도록 하라.
  • 최대 7개의 파라미터
  • 간단한 제어 흐름
    • indirect(mutual) recusion을 피하자.

Code Layout (Statements)

Braces

  • 여는 괄호는 이전의 statement와 같은 line에
  • 닫는 괄호는 혼자 하나의 line을 사용
  • 한 줄의 statement만 있더라도 brace를 사용.(for 문 또는 if 문에서)Statement Indentation
  • use 2~4 spaces. 단위 정해서 하나만 사용Demarcate Blocks with whitespace
  • 일부 블록들은 자연스럽게 구별이 되지 않을 수도 있음.
  • 이럴때는 blank 라인을 이용해서 분리시키자.
  • 코드 이해를 돕기 위한 것.
AAAAAA
AAA
AAAAA

BBB
BBBB
BB

CCCC

Alignment

  • 쉼표 뒤에 한 칸 띄우기
  • 배열 내부에 괄호와 한 칸 띄우기 or 붙여서 쓰기 등등

Split Complex Predicates Cleanly

  • 너무 긴 or 복잡한 조건문은 이해하기 쉽게 분리하기.

Multi-Line Statements

  • 아직 문장이 끝나지 않았음을 명시적으로 알 수 있도록 작성하거나
while (A < B &&
    C < D) 
    /// ...
  • 새로운 문장 시작 부분에 작성할 수도 있음
while (A < B
     && C < D) 
    /// ...

One Statement per Line

a = 0; b = 0; c = 0; print(a, b, c) # bad

Each Line Should Do One Thing

PrintMessage(++A, A+3) # bad

변수 이름 짓기

좋은 이름을 선택하기

  • 변수 이름을 정할 때, 잘 생각해서 정해야 함.
  • 의미 전달이 용이하게.
int birthdayDate;
int birthdayMonth;
int age;

이름 길이

  • 디버깅 시간을 최소화할 수 있음 -> 이름의 길이가 10~16일 때.
  • 짧은 이름이 명확하게 의미 전달이 되는지, 확인 할 것
    • read-optimize! not write-optimize. 읽는 사람을 생각하라.
  • 자주 사용하는 이름은 짧게, 자주 사용하지 않는 이름은 길게

반복문(루프) 인덱스

  • 보통 i, j, k 등을 사용
  • 루프 밖에서는 의미를 전달할 수 있는 이름을 사용하자.
    루프 안에서 카운트 된 변수가 루프 밖에서도 사용된다면.
readCount = 0;
    while (readBooks()) {
    readCound++;
    }
readingRate = readCount / booksTotal;
  • 긴 반복문 내에서는 인덱스 이름을 더욱 잘 구별하기 위해서 full index name을 쓰자
  • Avoid index cross talk in nested loops
    • 보통 i, j를 쓰기에 헷갈리는 경우가 많음
  • loop 인덱스로 i, j, k만을 사용하자. 그렇지 않으면 다른 개발자들이 코드를 볼 때, 헷갈릴 수 있음.

Computed-Value Qualifiers

  • 자주 사용되는 것: Total, Sum. Average, Max, Min ...
  • 변수 이름 마지막에 붙이자.
    • booksTotal, readsAverage
  • 에외: Num
    • 접두사로 사용 (numUsers)
    • 하지만 사용을 자제하기.(대신에 Count나 Total이라는 용어를 사용하자)(권장)

Use Common Opposites

  • begin/end
  • first/last
  • locked/unlocked
  • max/min
  • next/previous
  • old/new
  • opened/closed
  • visible/invisible
  • source/target
  • source/destiantion
  • up/down

Purpose-Driven Naming

  • 하나의 이름을 하나의 목적으로만 쓰기.
    • tmp와 같은 변수명 사용 X
  • Explicit names leads to clearer code

Status Variables

  • Avoid using flag in the name
    • it always means something, so name it accordingly
  • Use explicit variable names instead
# Bad

flag = 0x1;  
statusFlag = 0x80;  
printFlag = 16;  
computeFlag = 0;

#Good  
dataReady = true;  
characterType = CONTROL\_CHARACTER;  
reportType = ReportType\_Annual;  
recalcNeeded = false;

Avoid Hybrid Coupling

  • 숨은 의미가 있는 변수를 사용하지 말 것.
  • 예) bytesRead
    • # of bytes received를 의미
    • 0 보다 작을 경우 오류가 발생했음을 의미

Seperate NameSpaces

  • Java packages
    • can distinguish Database::Table from GUI::Table
  • C++ namespace keyword
  • 네임스페이스 기능이 없는 언어(C 언어)의 경우 naming convention을 이용

Use Enums Liberally


public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX,  
	SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE }

Boolean Variables

  • 일반적인 부울 이름을 사용
    • done, error, found, success, ok, ...
  • true/false 값만 가짐.
    • Bad: status, sourceFile
    • "is" 접두사를 사용하면 좋음.(isDone ...)
  • 긍정적인 의미를 가진 이름 사용을 권장.
    • isDone, isFail -> negate하기 좋음
    • isNotDone, isNotFail -> negate하면 헷갈림.

Shortening Names

  • Some abbreviation tricks
    • remove non-leading vowels(모음) (screen -> scrn, pages => pgs)
      • 한글에서 초성만 남기듯이
    • remove articles(관사) (and, the, ...)
    • remove useless endings (-ing, -ed, ...)
  • Abbreviate consistently (일관성)
    • "Standard Abbreviations" 문서를 작성할 수도 있음.
  • Should pass the telephone test
    • 소리내어 읽어보며 테스트(잘 읽히는가?)

Data Declaration

  • Put in comments what cannot go in name
  • Put unambiguous units in name of variable(명확한 단위를 표현)
    • if not possible, then at least put them in comments(불가능한 경우, 주석 첨부)Name to Avoid
  • 소리가 비슷한 단어(wrap vs rap)
    • telephone test!
  • 최소한 2개의 문자가 달라야함
  • 숫자 사용 X (num1, num2 ...)
  • 흔히 저지르는 typo 조심
  • 프로젝트에서는 1개의 언어(영어, 스페인어, 한국어 등등)을 사용하기.

Using Variables

Declarations & Initialization: Danger

  • Improper init => fertile source of bugs
    • result: variable has unexpected value
  • Know your programming language’s semantics!
  • Sources of bugs
    • not initialized at all (default in Java, random in C/C++)
    • inconsistent value (e.g., constructor initializes only part of the class)

Declarations & Initialization: what we can do

  • 초기화와 선언을 가까이 두자.
  • 선언과 초기화를 처음 사용하는 코드 라인과 가까이 위치
  • Be disciplined with initialization
    • 값을 명확하게 정해서 초기화 할 것. 언어에서 제공해준믄 default는 권장하지 않음
    • 모든 클래스 멤버는 constructor에서 초기화
    • method parameters: instead of initializing, these should be checked for validity
  • 변수의 reassignment를 막기 위해 final, const 같은 것들을 활용하자
    • constant를 원하는 경우 final static => init at class load time

Binding Variables to Values

  • Binding vs. flexibility
    • earlier binding -> less flexibility -> less complexity -> less risk of introducing errors
    • later binding -> more flexibility -> more complexity -> more risk of introducing errors
  • Can bind at
    • Coding time (i.e., use magic values) (i.e.,titleBar.color = 0xFF;)
    • Compile time (i.e., use named constants)
    • private static final int TITLE_BAR_COLOR = 0xFF;
      titleBar.color = TITLE_BAR_COLOR;
    • Run time (i.e, use properties file or Windows registry)
      titleBar.color = windowProperties.getProperty("TITLE_BAR_COLOR");
    • Object instantiation time: every time you create a window
    • Just-in-time: every time you draw a window

Using Variables: Summary

  • 내가 사용하는 프로그래밍 언어의 semantics를 숙지하고 사용
  • 선언부 근처에서 초기화
  • 처음 사용하는 곳 근처에 선언
  • Flexibility vs. reliability trade-off

Variable Span, Liveness, and Scope

Variable Span

  • space(LOC) between successive references
  • Programs 아래 항목들을 가지고 있을 수 있다.
    • 실행되긴 하지만, 전체적인 프로그램의 결과에 영향을 미치지 않는 코드.
    • 정의, 선언되기 전에 사용되는 변수
    • 메모리나 레지스터 할당이 필요한 변수
  • variable liveness는 위의 3가지 상황을 다루기 위한 것임.

Variable Liveness

  • Livenes는 변수의 property 중에서 데이터의 흐름에 관한 것.(“Is the value of this variable needed?”) (cf. dead code)
  • 각각의 명령(instruction)에서 프로그램 안에 있는 변수는 live or dead인 상태
  • 따라서 instruction의 시점에서 변수의 liveness를 따진다.

Semantic vs Syntatic

  • 2가지 종류의 liveness
    • Semantic liveness
    • Syntactic liveness
  • A variable x is semantically live at a node n if there is some execution sequence starting at n whose (externally observable) behavior can be affected by changing the value of x.
int x = y * z; # x는 live
return x; 
int x = y * z; # x는 Dead

...
x = a + b; 
...

return x; 
반응형