태그 : eclipse

Allman 식 이클립스 Java 코딩 스타일 프로파일

어떤 자바 코딩 스타일을 쓰시고 계신가요?

특별히 선호하는 스타일이 없으시다면 아마도 자바 코딩 규약을 따르시겠죠?

코딩 스타일이라고 하면 여러 가지가 고려할 것들이 있습니다. 들여쓰기를 어떻게 하는지, 블럭 지정은 어떻게 하는지, 언제 줄을 나눌 것인지, 띄어쓰기, 코멘트, 배열 초기화, 심지어 이름 정하는 규칙까지......

이런 여러 요소가 있지만 보통 코딩 스타일을 분류할 때에는 들여쓰기와 블럭 표현 방법을 주로 봅니다. 아마도 이 두 가지가 코딩 스타일의 외형에 가장 큰 영향을 주기 때문인 듯합니다. 몇몇 대표적인 블럭 표현 방법에는 따로 부르는 이름까지 붙어 있지요.

제가 프로그래밍을 배우기 시작할 때에는 베이식, 어셈블리, 포트란, 코볼 같은 언어들을 주로 사용했기 때문에 요즘과는 다른 코딩 스타일을 썼었습니다. 언어 구조가 좀 다르니까요. 제가 배운 베이식은 서브루틴 같은 것도 없었거든요. ^^

처음으로 배운 구조적 언어는 Pascal입니다. Apple II에서 돌아가는 UCSD Pascal이 있었는데 p-System이라는 가상 머쉰 위에서 p Code라는 중간 코드로 컴파일 되는 언어입니다. 지금 우리가 쓰는 자바 가상 머쉰과 비슷한 놈이었죠. 좀 다른 것은 JVM은 OS 위에서 돌아갔지만 p-System은 OS까지 포함하고 있습니다. 그다음에는 CP/M이라는 OS에서 Turbo Pascal로 프로그래밍을 했었고요.

좌우간 이런 이유로 Pascal처럼 블럭의 시작과 끝이 명시적인 Allman 스타일의 블럭 표현 방법을 선호하게 되었나 봅니다. K&R 스타일은 블럭의 시작 기호와 끝 기호를 신경 써서 주목하지 않으면 찾기가 힘들더라고요. 물론 요즘은 IDE를 쓰기 때문에 자동으로 찾아주기는 하지만 최근까지 VI로 개발했었기 때문에 이 스타일이 아니면 코드를 전혀 보지 못하는 지경입니다.

대표 Indent Style

말을 시작했으니 대표적인 코딩 스타일을 몇 가지 적어볼까요? 마침 위키 백과에 잘 정리가 되어 있군요.

K&R 방식

for (int i = 0; i < 10; i++) {
    s = s + i;
    if (s > 10) {
         ......
    } else {
         ......
}

자바 코딩 규약에서 사용하는 방식입니다. 우리나라에서는 이것이 가장 일반적인 듯합니다. C를 만든 커닝핸과 리치씨의 "The C Programming language"라는 책에 사용된 코딩 스타일이지요. 이 책 한 권씩 안 사본 사람이 없을 듯한데 요즘은 모르겠군요. 제가 처음으로 산 원서 같기도 하고...... 들여쓰기는 원래 8칸이지만 요즘은 4칸을 주로 씁니다.

이것의 변형으로 BSD KNF Style이 있다네요. 보통 kernel style이라고 부르는 놈입니다. 저는 이것과 K&R이 같은 것인 줄 알았는테 텝이 조금 다르군요. 하드 탭(탭문자)는 8칸으로 보이게 설정하고 소프트 탭(어이지는 공백 여러개로 탭을 표현)은 공백 4개로 설정합니다. 밑에 제 스크린샷 중 첫번째에서 Tab Policy를 Mixed로 하고 Use tabs only for leading indentations를 체크한 후에 블럭 들여쓰기 할 때에 tab을 두번 치면 비슷해질 듯 하네요.

이렇게 탭을 설정하고는 블럭을 들여쓸 때에는 하드탭으로 이어지는 줄을 들여쓸 때에는 소프트탭으로 처리한다고 합니다.

Allman 방식

for (int i = 0; i < 10; i++)
{
    s = s + i;
    if (s > 10)
    {
         ......
    }
    else
    {
         ......
    }
}

Sendmail과 많은 BSD 유틸리티들을 만든 Eric Allman의 코딩 스타일입니다. BSD Style이라고도 불렀었습니다. 원래는 들여쓰기를 공백 8칸으로 하는데 요즘은 4칸으로 합니다.

보시면 알겠지만 블럭의 시작과 끝이 명확합니다. 가독성이 높지요. 코드 한 줄씩 정확히 볼 수 있습니다. 단 한 화면에 보이는 코드 양이 많지 않아서 스크롤을 더 해야 하는 단점도 있습니다. 그래서 Cut & Paste 방식의 프로그래밍을 방해해서 저는 좋은데 다른 분들은 모르겠군요.

C에서는 가장 많이 사용하는 방식이라고 합니다.

Whitesmith 방식

for (int i = 0; i < 10; i++)
    {
    s = s + i;
    if (s > 10)
        {
         ......
        }
    else
        {
         ......
        }
    }


Whitesmith C라고 한참 잘 팔리던 C 컴파일러의 코딩 방식입니다. 저는 이 방식으로 코딩하는 사람을 한 번도 못 봤지만 Whitesmith C로 장난질을할 때에 잠깐 접해 보기는 했습니다. 어떻게 보이시나요? Allman 방식에 눈이 익어서 처음에는 적응하기 어렵지만 금방 적응이 되더군요.
이 방식 역시 원래 8칸이었지만 요즘은 4칸을 씁니다.
Allman 방식과 거의 비슷한 수준으로 많이 쓴다고 합니다.

GNU 방식

for (int i = 0; i < 10; i++)
  {
    s = s + i;
    if (s > 10)
      {
         ......
      }
    else
      {
         ......
      }
 }

GNU에서 사용하는 방식입니다. 아마도 리처드 스톨만의 방식이겠죠? Allman과 Whitesmith의 중간형으로 보입니다. 나름의 이유가 분명히 있겠지만 솔직히 전 이 방식을 별로 좋아하지 않습니다.  이렇게 작은 들여쓰기가 반복되면 가독성이 떨어지더군요. 눈이 어지럽습니다. 보통 2칸씩 두 번 들여씁니다.

위키 백과에는 pico 방식과 banner 방식도 설명하고 있는데 이것들은 그렇게 많이 쓰이지 않으므로 넘어가겠습니다.

이클립스 자바 코드 스타일 프로파일

좌우간 제가 이 글을 쓴 이유는 이런 방식 중에 제가 쓰는 allman 방식의 이클립스용 코딩 스타일 프로파일을 공개(?)하려는 것입니다.
혹시 allman 방식을 좋아하시는 분이 있다면 받아서 쓰세요. 제가 쓰던 것을 약간 손 봐서 올립니다.

allman.zip

이 파일을 내려 받아 압축을 푼 후에 이클립스의 자바 코드 스타일 프로파일로 등록 하십시오.

Window > Preferences > Java > Code Style > Formatter 에서 Import 하시면 됩니다.

설정 내용


간단히 설정 화면 갈무리한 것을 올려보겠습니다.

들여쓰기

들여쓰기는 공백 4칸입니다. 탭을 4칸으로 표시되도록 하는 방식은 다른 에디터에서 보면 다르게 보이기 때문에 탭은 8칸으로 보이게 했습니다.
저는 에디터를 고를 때에 들여쓰기를 탭 문자가 아닌 공백으로 처리할 수 있는지를 꼭 확인합니다.

대괄호

이 부분에서 Allman 방식의 대표 특징을 부여합니다.

빈 줄 삽입

널찍널찍한 코드가 가독성이 좋지요. ^^
가독성이 떨어지면 코드를 통제하기 힘들어지고 버그도 많이 생깁니다. cut & paste 해 놓고 "잘 돌아가던 코드인데 왜 안 돌아가지?" 하는 사람 많이 봤지요. 프로그래머는 코드 한 줄에 책임을 져야 하는 거라고 생각합니다. "네가 만들어 놓은 코드를 가져다 썼는데 작동 안 되니 네가 책임져"라고 말하는 프로그래머 보면 참 답답합니다. 자기가 제다이인 줄 알고 감으로 프로그래밍하죠.

줄 나누기

자바 코딩 규약과 비슷합니다. (아마도... ㅡ.ㅡ);


제어 코드

이 부분도 기본은 널찍널찍...


긴 줄 나누기

80칸에 맞춰서 긴 줄을 나누게 설정했습니다. 요즘은 화면이 넓으니 화면 가득한 크기로 에디터를 키우고 프로그래밍하는 사람들이 많습니다. 요즘 같은 시대에 누가 터미널을 쓴다고 80칸에 맞추느냐고 말하는 분들 많지요. 자바 코딩 규약에 쓰여 있는 것처럼 다양한 환경에서도 같은 모습을 유지하려면 80 칸에 맞추는 관례를 지키는 것이 좋기는 하지요.
저는 조금 다른 이유로 여전히 80칸에 맞춰서 코딩합니다. 가로로 길게 늘여 놓으면 눈에 잘 안 들어오기 때문입니다. 눈알을 이리저리 계속 굴려야 하거든요. 제가 노안이라서 그런가요? :-)
한번 해보세요. 진짜 코드에 대한 장악력이 높아집니다. 제 생각에 80칸 규칙을 에디터가 제한하도록 설정하는 것은 별로 좋은 것 같지는 않습니다. 어떤 줄은 이름이 너무 길다거나 해서 80칸을 넘는 것이 오히려 나을 수도 있으니까요. 그냥 기준선만 표시하고 프로그래머가 그런 습관을 지키도록 하는 것이 좋다고 생각되는데 일단 이 프로파일에서는 강제로 줄 나누기 하도록 했습니다.


주석 처리

이 부분은 그냥 제가 좋은 쪽으로 했는데 뭘 고쳤는지 모르겠네요.  ㅡ.ㅡ;


따~라 라~라 랄랄랄라 랄랄랄라~
따라라 라~라~ 라~



감사합니다. 혹시 문제가 있으면 리플 달아주세요.


by 박성철 | 2008/01/18 16:04 | 프로그래밍 이야기 | 트랙백(1) | 덧글(11)

[번역] 자바 실행코드를 추적하는 5가지 방법

Zviki Cohen씨의 Five ways for tracing Java execution을 번역했습니다.

----------------------

난 종종 내가 만들지 않은 코드의 속을 파고 들어야 하는 상황에 직면하곤 한다. 이들 대부분은 문서가 형편 없고 어떤 경우는 소스의 일부만을 가지고 있는데 이는 나머지 부분을 디컴파일 해야 하는 것을 의미한다. 이건 지겨운 탐험이다. 이런 일을 해야 할 이유 중 큰 두가지는 코드를 유지보수하기 위해서 또는 그것을 사용하기 위해서이다. 후자는 제3자 프레임워크와 클래스 라이브러리 같이 내가 뭔가를 구축하는데 필요한 것들을 말한다. 예를 들어 내가 이벤트 핸들러의 인터페이스를 상속해 구현 하려고 하는데 어떤 이벤트가 정확히 어떤 시점에 어떤 인수를 받을 것인가에 대해 애매 할 수 있다.

난 보통 실행시에 코드를 추적하는 것이 보다 빠르다는 사실을 발견한다. 특히 이 코드가 자명하지 않은 클래스들간의 링크, 예를 들어 한 인터페이스에 여러 구현체가 있고 실행시 이 중 어떤 것을 사용할지 선택 한다거나 하는 경우에 말이다. 잡동사니 같은 설계 도구들로는 정말 충분하지 않다.

이 포스트에서 나는 실행시 코드를 추적하는 일반적인 방법들을 정리하려한다. 이 팁들과 예제들은 이클립스를 사용하는 것으로 가정하지만 대부분은 다른 IDE로도 따라 할 수 있을 것이다. 추후에 밑에 거론된 기술들에 대한 보다 자세한 정보를 제공하려고 한다.

기초 : 중단점_Breakpoint들과 단계별 실행

가장 단순한 방법부터 시작을 해보면, 먼저 중단점를 설정하고 실행 코드 추적을 시작해라.


장점단점
  • 설정하고 사용하기 매우 단순하다. 실지로, 디버거를 실행하기만 하면 된다.
  • 모든 정보에 접근할 수 있다. 메소드 전달인수와 지역 변수 등등
  • 코드를 소정하지 않는다.
  • 선택적 : 어느 부분에서 실행을 멈출지 결정할 수 있다.
  • 코드를 한 단계씩 추적하는 것은 너무 오래 걸린다. 무엇보다, 계속 주목해야 한다는 것. 매 단계마다 더 깊이 들어가야 할지 넘어갈지 빠져나올지를 결정해야 한다. 이 때문에 이 방법은 실용적이지 않다.
  • 이벤트 핸들러를 디버깅 할 때 어떤 메소드가 호출될지 모른다면 모든 메소드들에 중단점을설정해야 한다.
  • 소스를 가지고 있지 않는 한 메소드 내부에는 중단점을 설정할 수 없다.

최적의 상황:  빠르고 단순한 방법이 필요하고, 모든 코드를 가지고 있으며 어느 부분에서 멈춰야 하는지 알있을 때. 특정 위치의 자세한 정보(전달 인수, 지역 변수 등)가 필요한 경우.

팁: 모든 소스코드를 가지고 있지 않다고 해도 메소드 중단점이나 클래스 로딩 중단점을 설정해서 메소드나 클래스에 들어갈 때 멈추게 할 수 있다.

  • 클래스 로딩 중단점은 단순하게 이클립스 Run menu의 Add Class Load Breakpoint... 메뉴로 설정 할 수 있다.
  • 메소드 중단점을 설정하기 위해서는 클래스 파일을 먼저 디컴파일 해야 한다. JadClipse plug-in을 사용하도록 한다. 디컴파일을 한 후 메소드를 골라 Run 메뉴의 "Toggle Method Breakpoint"를 선택한다. 디컴파일 한 소스에 일반 중단점 역시 설정할 수 있지만 작동하지는 않는다.

원초적: 디버그 메세지

디버기 메세지 설정하기로 계속해보자. 가장 단순한 방법은 System.out.print 명령을 사용해서 콘솔로 메세지를 출력하는 것이다. 다음 단계는 아마도 로깅 메카니즘( JDK logging, Apache Commons Logging, Log4j)을 사용하는 것이 될 수 있다.


장점단점
  • 원하는 부분을 정확히 선택 가능.
  • 실행이 빠르다. 너무 많은 메세지를 출력하지 않는 한......
  • 관심있이 있는 정보를 정확히 출력할 수 있게 해준다.
  • 코드를 변경해야만 한다. 이 때문에 소스를 가지고 있지 않다면 이 방법은 소용이 없다.
  • 설정하는데 시간이 걸린다. 어느 부분을 살펴보아야 하는지 확실이 모를 경우 여러 메소드에 디버그 메세지를 삽입해야 한다.
  • 코드가 지저분해지고 후에 디버그 메세지들을 제거하지 않을 경우 실행시 부하가 생긴다.

최적의 상황: 코드를 가지고 있고 어디를 살펴보아야 할지에 대해 좋은 생각이 있는 경우. 이벤트 핸들어에 좋은 해법이다. 복잡한 흐름이 실행되는 중에 어떤 이벤트가 발생하는지 이해하는데 효율성이 높아 실용적이다.

팁: 지금 실행중인 메소드를 출력해주는  제너릭 메소드를 만드는 것은 쉽다. 내가 즐겨쓰는 가장 좋은 방법은 스텍 트레이스를 얻는 것이다. 호출 스택 중 마지막 엔트리가 디버그 메세지 메소드가 될 것이다. 그 엔트리 전의 것들은 그것을 호출하는 메소드들이 된다. 스택 트레이스를 얻는 방법은 다음과 같다.

  • JDK 5.0 이후: Thread.currentThread().getStackTrace()를 사용한다.
  • 이전 (JDK 1.4): 새로운 익셉션 인스턴스를 만들고 이 새 인스턴스에서 getStackTrace를 사용해서 호출 스택을 얻는다. 이 인스턴스를 throw 할 필요는 없다..

쟁점: 동적 프록시_Dynamic Proxy
단순한 디버그 메세지 보다 향상된 방법이다. Dynamic Proxy는 자바의 특별한 기능으로 개발자가 프록시 클래스를  도입해 기존 클래스 앞에 놓고 기존 인터페이스로 들어오는 호출들을 가로챌 수 있게 해준다. 일단 호출을 가로채고 나면 필요한 모든 정보가 포함된 적절한 디버그 메세지를 출력 할 수 있을 것이다.

장점
단점
  • 디버그 메세지로 코드를 어지럽힐 필요가 없다. 디버그 메세지를 한곳에 모아 놓을 수 있다.
  • 작업이 끝나면 간단히 한번에 제거 할 수 있어 성능에 영향을 주지 않는다.
  • 인터페이스를 통해서만 작동이 된다. 퍼블릭 메소드건 아니건 인터페이스에 정의 되지 않으면 사용할 수 없다.
  • 코드 수정이 필요: 코드를 보유하고 있어야 한다.
  • 선택적으로 메세지 프린트를 할 수 없다.

최적의 상황: 이벤트 핸들러에 최고의 해법. 몇초만에 제너릭프록시로 깡통 이벤트 핸들러를 만들어 이벤트의 순서를 볼 수 있다. 이벤트 핸들러들을 이해하려 할 때에 가장 단순하면서도 빠른 방법이다.


팁: Sun의 사이트에서 제너릭 동적 플락스 코드를 찾을 수 있다. 이것은 대부분 좋지만 한가지 작은 제약이 있는데 프록시로 감싸게 될 인스턴스의 클래스가 직접 구현했던 인터페이스들만을 임플리먼트 한다. 그 조상들의 어떤 인터페이스도 임플리먼트하지 않는다.  이 문제는 조상들의 목록을 따라가며 모든 인터페이스들을 뽑아내는 것으로 쉽게 수정할 수 있다. 앞으로 올릴 포스트들 중 하나에서 좀 더 나은 방법을 제시하겠다.


무차별 공격: 실행시 프로파일러

프로파일러는 특별한 JVM 훅으로 모든 호출을 추적하는 강력한 도구이다. 좌우간, 이것은 왠지 반 인치짜리 못에 10 파운드짜리 해머를 쓰는 것 같다.

장점단점
  • 코드 변경이 필요 없다.
  • 소스코드가 없어도 모든 실행코드를 추적할 수 있다.
  • 대부분의 도구에 관심밖의 데이터를 선별해서 보는 기능이 있다.(JDK 호출, getters와 setters 등등)
  • 대부분의 좋은 도구들은 고가이다.
  • 대부분의 도구는 설치하고 사용법을 배우는데 시간이 필요하다.
  • 프로파일링은 시스템 성능을 떨어트릴 것이다. 이 때문에 프로파일러가 정보를 수집하는 동안  실행하는 것은  실용적이지 않다.
  • 대부분의 도구가 성능 측정에 촛점이 맞추어져있어서 실제 수행 시간에 따른 실행 경로는 무시한다.
  • 대부분의 도구가 호출만 지원하고 인자는 지원하지 않는다.

최적의 상황: 매우 특별한 동작에 대한 완전한 그림은 원할 때 (예를 들어 매운 짧은 실행 흐름)

팁: 좋은 도구의 구입비는 시트당 500불 정도 이다. 대부분의 무료 도구들은 기본적 수준의 기능만 가지고 있다. 이 작업을 위한 최고의 무료 오픈소스 도구는 Eclipse Testing and Performance Tools Platform (TPTP)이다. 이 도구를 사용해본 좋은 경험을 가지고 있어 추천한다. 이것은 어떻게 실행되는지 이해하기에 가장 좋은 방법 중 하나인 sequence diagram을 제공한다. TPTP를 사용하곤 했었는데 내가 맥으로 바꾸기고 보니 호환이 되지 않았다. 여유 시간이 좀 있었으면 수정하려고 시도했을 것이다.


새시대: Aspects

Aspect Oriented Programming (AOP)는 단순하지 않은 아이디어이다. Aspects의 개념은 빼고 단순히 결론만 한마디로 말한다면, '빠르고 쉽게 코드의 실행을 가로채는 방법'이다. 원소스코드의 변경 없이 메소드, 생성자, 필드 접근등의 주위에 후크를 선별적으로 걸 수 있다. 이 후크안에서 디버그 메세지를 출력 할 수 있다.

장점단점
  • 매우 빠르고 쉽게 설정할 수 있다.
  • 선별적: 원하는 클래스나 메소드만을 추적 할 수 있다.
  • 인수를 포함한 모든 정보를 제공한다.
  • 소스코드를 변경하지 않으며 작업이 끝난 후 제거하기도 매우 쉽다.
  • 성능이 좋아 장시간 실행에도 사용 할 수 있다.
  • AOP에 대한 기본적인 이해를 필요로 한다. 특히 복잡한 필터를 추가하기 위해.
  • 코드를 다시 구축해야 한다. JAR 패키지에 있는 코드를 추적하려 할 때 문제가 될 수 있다.

최적의 상황: 다시 구축 할 수 있는 실행 코드를 추적하려고 할 때

팁: 그냥 사용하라. AOP는 아직 주류에서 멀리 떨어져 있다. 언제 주류에 이를지도 확실하지 않다. 품질이나 사양에 대한 논쟁을 차치하고 대부분의 개발자들은 한시간 안에 AOP 기반의 로깅을 설정해서 실행할 수 있다. 앞으로 올린 포스트에서 정확한 사용 단계를 보여 주려 한다. 이클립스 사용자라면 Aspect Java Development Toots (AJDT)를 추천한다.


결론

어떤 방법을 선택했나요? 두가지 서로 다른 경우로 나누려 합니다. 실행 코드의 짧은 부분을 완벽하게 추적할 것이냐 아니면 주어진 클래스나 계층으로 들어가거나 거꾸러 여기서 발생하는 이벤트들을 추적할 것이냐.


실행을 완벽히 추적하려 할 때:

  1. 프로파일러가 가장 단순한 방법이다. 내 생각에 모든 개발자들은 프로파일러를 작동할 줄 알아야 하고 군수창고에 운영할 수 있게 준비된 것 하나를 가지고 있어야 한다.
  2. 다음 선택은 AOP가 될 수 있다. 이것이 두번째 선택인 이유는 JAR 패키지로 작업하기 단순하기 때문이다.  좌우간, AOP는 더 많은 제어 능력을 가지고 있따. 예를 들어 메소드 인수를 살펴보고 출력 할 수 있다.
  3. 디버그 메세지를 사용해라.

이벤트를 추적하려고 할 때:

  1. AOP를 사용. 관심있는 호출만 선별해서 잡아내라.
  2. 동적 프록시를 사용. 디버그 메세지를 사용하는 것과 유사하지만 보다 멋진 해법이다. AOP가 처음에는 복잡 할 수 있지만 오랫동안 실행하는 경우에는 난 AOP로 갈 것이다.
  3. 디버그 메세지를 이용해라.
  4. 중단점을 이용해라.

보는 것 처럼 이 문맥에서 난 중단점을 좋아하지 않는다. 중단점은 자신의 코드를 디버깅 할 때에는 아주 훌륭하다. 그렇지만 실행 추적에는 그렇지 않다. 이를 하는데에는 보다 더 효율적인 방법들이 있다.


갱신: 몇몇 독자들이 지적한 것 처럼 AspectJ는 패키지된 JAR를 다루는데 사용 할 수 있다. 나중에 이 선택사항과 AspectJ을 탐구한 글을 올릴 예정이다.

by 박성철 | 2007/12/11 18:12 | 프로그래밍 이야기 | 트랙백(1) | 핑백(1) | 덧글(4)

◀ 이전 페이지다음 페이지 ▶