의미있는 이름

  • 이름은 패키지, 클래스, 메소드, 변수 등 널리 사용된다.
  • 이름을 잘 지으면 여러모로 편하다.

의도를 분명히 밝혀라

  • 좋은 이름을 지으려면 시간이 걸리지만 좋은 이름으로 절약하는 시간이 훨씬 더 많다.
  • 코드를 보고 더 나은 이름이 떠오르면 즉시 개선하는 것이 좋다.
  • 이름에 주석이 필요하다면 의도를 분명히 드러내지 못한 것이다.
    • ex) int d; // 날짜

그릇된 정보를 피하라

  • 일반적으로 떠오르는 생각을 왜곡시키지 말라.
  • 중의적으로 해석될 수 있는 이름은 지양하라.
  • 코드의 일관성을 깨뜨리지 말라.

    ex)
    String codeList; 
    // 실제 데이터를 담는 컨테이너가 List가 아닌데 변수명으로 list를 사용하는 경우
    
    int a = l; 
    if (O == l)
     a = 01;
    else
     l = Ol;
    // 문자 l은 숫자 1처럼 보이고 문자 O는 숫자 0 처럼 보인다.

의미있게 구분하라

  • 불용어(noise word)를 피하라.
    • ex) int a1, a2, a3;
  • 읽는 사람이 차이를 알수 있도록 이름을 지어라.
  • 정확한 개념이 구분이 되지 않는다.
    • ex) ProductInfo? ProductData?

발음하기 쉬운 이름을 사용하라

  • 두뇌는 단어를 바탕으로 발음하려고 한다.
    • ex) genymdhms -> generateTimestamp

검색하기 쉬운 이름을 사용하라

  • 상수는 검색하기 쉽도록 변수로 정의해서 사용하라.
  • 긴 이름이 짧은 이름보다 검색하기 수월하다.
  • 이름 길이는 범위 크기에 비례해야 한다.
  • 간단한 메서드에서나 짧은 변수명을 사용하라.

인코딩을 피하라

  • 불필요한 정신적 부담일 뿐이다. (변수에 부가정보를 덧붙이는 표기. 해독, 발음, 오타)
  • 헝가리식 표기법
    • 변수명에 타입을 명시한다. 타입이나 이름이 바뀌더라도 반드시 같이 변하진 않는다.
  • 멤버변수 접두어
    • 코드를 읽을수록 접두어/접미어는 관심 밖으로 밀려난다. 구닥다리 코드의 징표일 뿐이다. ex) String m_title, strContent;
  • 인터페이스 클래스와 구현 클래스
    • 때론 구분하기 위해서 인코딩이 필요할 때도 있다.
    • ex) 인터페이스 보다는 구현 클래스를 인코딩 하라. ServerManagerImpl, CServerManager (O) / IServerManager (X)

자신의 기억력을 자랑하지 마라

  • 독자가 코드를 읽다가 변수명을 변환하게 해서는 안된다.
    • 이미 변수 a와 b가 있다고 c라는 이름을 선택하는 논리는 최악이다.
  • 똑똑한 프로그래머와 전문가 프로그래머의 차이점은 명료함이다. 다른 사람들이 잘 알아볼수 있도록 코딩해야 한다.

클래스 이름

  • 클래스/객체 이름은 명사/명사구가 적합하다.
    • Manager, Processor, Data, Info와 같은 단어는 피하라.
    • ex) Customer, AddressParser
  • 동사는 사용하지 않는다.

메서드 이름

  • 메서드 이름은 동사/동사구가 적합하다.
    • ex) deletePage, saveBoard
  • 변경자, 접근자, 조건자는 각각 set, get, is로 시작하라.
    • ex) getItem, setName, isStudent

기발한 이름은 피하라

  • 구어체/속어는 사용해서 안된다.
  • 특정 문화에서만 사용되는 사례도 금한다.
    • ex) kill() -> whack() / abort() -> eatMyShort()

한 개념에 한 단어를 사용하라

  • 똑같은 메서드를 클래스마다 get, fetch, retrieve 등 다른 단어로 혼용하면 혼란스럽다.
  • 일관성 있는 어휘가 독자에게 좋다.

말장난을 하지 마라

  • 한 단어를 두가지 목적으로 사용하지 마라.
  • 다른 개념에 같은 단어를 사용한다면 그것은 말장난에 불과하다.
    ex) 
    지금까지 구현한 모든 add 메소드가 기존 값 두개를 더하거나 이어서 새로운 값을 만든다고 가정하자. 
    새롭게 작성하는 메소드는 집합에 값을 하나만 추가한다. 
    일관성 있게 add라는 메소드명을 사용해야 하는가? 아니다. 
    insert나 append 등 다른 이름을 사용하자.
  • 최대한 이해하기 쉽게 작성해야 한다.
  • 집중적인 탐구가 필요한 코드가 아닌 대충 훑어봐도 이해할 수 있는 코드 작성이 목표다.

해법 영역에서 가져온 이름을 사용하라

  • 코드를 읽을 사람도 프로그래머라는 사실을 명심한다.
  • 전산용어, 알고리즘 이름, 패턴 이름, 수학용어 등을 사용해도 괜찮다.
  • 기술적인 개념에는 기술적인 이름이 가장 적합한 선택이다.
    • ex) queue, stack

문제 영역에서 가져온 이름을 사용하라

  • 적절한 용어가 없다면 문제 영역에서 이름을 가져온다.
    • 코드를 유지 보수하는 개발자가 분야 전문가에게 의미를 물어 파악할 수 있다.
  • 우수한 개발자와 설계자라면 해법 영역과 문제 영역을 구분할 줄 알아야 한다.

의미 있는 맥락을 추가하라

  • 스스로 의미가 분명한 이름은 있다. 하지만 대다수 이름은 그렇지 못하므로 클래스, 함수, 이름 공간에 넣어 맥락을 부여한다.
  • 모든 방법이 실패하면 마지막 수단으로 접두어를 붙인다.
    ex)
    firstName, lastName, street, houseNumber, city, state, zipcode 라는 변수가 있다. 
    변수를 훑어보면 주소라는 사실이 금방 알아챈다. 
    하지만 어느 메소드가 state라는 변수 하나만 사용한다면? 
    변수 state가 주소의 일부라는 사실을 금방 알아챌까? 
    addr 접두어를 추가해 addrFirstName, addrLastName, addrState라고 쓰면 맥락이 분명해진다.

불필요한 맥락을 없애라

ex)
 Gas Station Deluxe 라는 어플리케이션을 작성한다고 해서 클래스 이름 앞에 GSD를 붙이지는 말자. GSDAccount, GSDUser ..
 G를 입력하고 자동완성을 누를 경우 모든 클래스가 나타나는 등 효율적이지 못하다.
 개발자를 지원하는 IDE를 방해할 이유가 없다.

마치며

좋은 이름을 선택하려면 설명 능력이 뛰어나야 하고 의미가 뚜렷한 어휘인지 분별할 줄 알아야 한다.
다른 개발자가 반대할까 두려워 이름을 바꾸지 않아서는 안된다. 
나름대로 수정했다가 질책을 받더라도 개선하려는 노력을 중단해서는 안된다. 
그래야 자연스럽게 읽히는 코드를 짜는 데에 더 집중할 수 있다. 
단기적인 효과는 물론 장기적인 이익도 보장한다.

참고문헌 - CleanCode 애자일 소프트웨어 장인 정신

'Development > CleanCode' 카테고리의 다른 글

Formatting  (0) 2018.03.02

multiple 'X-Frame-Options' headers with conflicting 이슈 해결

동일 도메인에서 <iframe>을 통해 접근하는 경우 X-Frame-Options을 DENY로 설정하면 최신(?) 브라우저에서는 접근할 수 없는 문제가 발생할 수 있다. 이 경우 동일 도메인에서는 <iframe> 접근이 가능하도록 X-Frame-Options를 SAMEORIGIN으로 설정해줘야 한다.

<iframe>을 사용하는 부분이 있어 기존에 아래와 같이 SAMEORIGIN으로 설정해서 잘 사용하고 있었다.

http.headers().addHeaderWriter(new XFrameOptionsHeaderWriter(XFrameOptionsHeaderWriter.XFrameOptionsMode.SAMEORIGIN));

그런데 스프링 시큐리티 버전(3.2.3 -> 4.0.4)을 올리면서 동작에 문제가 생겼다. 브라우저에서 아래와 같은 에러가 발생했다.

이슈

[Chrome]
in a frame because it set multiple 'X-Frame-Options' headers with conflicting values ('DENY, SAMEORIGIN'). Falling back to 'deny'


http 응답 헤더를 보니 DENY와 SAMEORIGIN 설정이 중첩되는 문제가 발생했다.
스프링 시큐리티 버전이 올라가면서 default 값인 DENY에 SAMEORIGIN이 추가되어 충돌난 듯하다.

해결방안

내용을 찾아보니 스프링 시큐리티 4.x 부터 설정하는 방식이 변경되었다.

http.headers().frameOptions().sameOrigin();

위와 같이 설정하니 문제없이 잘 동작하는 것을 확인했다.

'Development > Spring' 카테고리의 다른 글

DatabaseConfiguration 적용  (0) 2018.08.17
Configuration Condition  (0) 2018.07.16
비동기 메소드 HttpServletRequest 에러  (0) 2017.12.03
비동기 어노테이션  (0) 2017.11.25
캐시 어노테이션  (0) 2017.10.06

비동기 메소드 HttpServletRequest 이슈 해결

@Async로 선언된 비동기 메소드를 호출했다. 메소드는 해당 클래스에 @Autowired된 HttpServletRequest로 부터 정보를 가져오다가 SimpleAsyncUncaughtExceptionHandler.handleUncaughtException() 예외가 발생했다.

No thread-bound request found: Are you referring to request attributesoutside of an actual web request, or processing a request outside of theoriginally receiving thread.

원인은 비동기 처리시 다른 스레드에서 동작하기 때문이다.

해결방안

  • request로 부터 필요한 정보를 메소드의 파라미터로 전달한다.
  • 다음과 같이 RequestContextHolder에서 현재 HttpServletRequest를 가져온다.
// WebApplicationInitializer 설정에 리스너 추가
servletContext.addListener(new RequestContextListener());

ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = attr.getRequest();


'Development > Spring' 카테고리의 다른 글

DatabaseConfiguration 적용  (0) 2018.08.17
Configuration Condition  (0) 2018.07.16
multiple 'X-Frame-Options' headers with conflicting 에러  (0) 2017.12.15
비동기 어노테이션  (0) 2017.11.25
캐시 어노테이션  (0) 2017.10.06

+ Recent posts