레이블이 coding tip인 게시물을 표시합니다. 모든 게시물 표시
레이블이 coding tip인 게시물을 표시합니다. 모든 게시물 표시

2014년 12월 31일 수요일

초보 개발자가 꼭 알아 두어야 할 다섯 가지 기술들

 오늘은 아무도 가르쳐 주지 않는, 그리고 이제 와서 누군가 에게 물어보기도 뻘쭘한 초보 개발자를 탈출하기 위해 필요한 테크닉에 대해 이야기 해 보고자 한다.

 초보 개발자가 고급 개발자가 되어가는 과정을 한마디로 정의하자면 "좀 더 게을러지기 위한 강렬하고 적극적인 의지의 표현"이 되겠다. "생산성"이니 "효율성", "정확성"같은 것 들은  프로그래머에게 있어서 부수적으로 얻어지는 것일 뿐 목적이 될 수 없다. 오로지 끊임없이 편하고 게을러지기 위한 노력만이 있을 뿐이다.


1. 마우스 안 쓰기

오늘날의 컴퓨팅 환경은 시간과 청각과 같은 인지 영역에 의거한 인간의 자연스러운 본능에 모든 행동이 정의되고 제약되는 게슈탈트 심리학의 세계이다. 그러니까 버튼은 누르고 싶게 생겨야 하고 이벤트 알람은 귀에 거슬리게 하여 주의를 끌 수 있어야 한다. 하지만 프로그래밍의 세계는 추상의 세계이다. 보이지 않는 본질을 파악하고 이를 다시 추상화 해 나가는 작업의 반복인 것이다.
 이러한 이유로 필자는 마우스(터치패드나 트랙패드를 포함) 안 쓰기를 초보 프로그래머에게 있어서 익혀야 할 기술의 첫번째로 이름을 올렸다.

 결론부터 말하자면 마우스는 프로그래머의 적이다. 마우스는 인체공학적인 면에 있어서도 손가락만 움직이면 되는 키보드와는 그 편의성과 정확성,속도면 에서 엄청나게 차이가 날 뿐만 아니라, 심리학에서 말해지는 몰입(flow) 상태를 방해 한다는 점에서도 프로그래머와는 궁합이 좋지 않다.

명필은 붓을 가리지 않는다고 하지만
손에 맞는 키보드 선택은 개발자에게 무척 이나 중요하다.
하지만 키보드 사는데 수 십 만원 썼다고 하면 사람들은 내가 음악가 인줄 알겠지?

 그럼에도 불구하고 마우스를 사용하게 되는 것은 순전히 직관에 끌리는 사람의 본능 때문 이다. 오늘날의 컴퓨팅 환경은 직관, 즉 시각과 청각을 최대한 활용하도록 설계되고 있다. 그러니까 마우스를 사용하지 않는 다는 것은 자연스러운 본능과의 싸움인 것이다. 하지만 걱정하지 말라, 결국 컴퓨팅 환경을 만들어내고 있는 것 들 또한 프로그래머 이며, 이들은 자신이 만든 프로그램에 키보드 사용자를 배려한 여러 장치를 해 놓는다. 단축키와 매크로 같은 것들 말이다.

 일단 오늘부터라도 작업에 주로 사용하는 어플리케이션의 주요 기능들을 반드시 단축키를 사용해서 진행하는 습관을 들여보자. IDE뿐만 아니라 워드나 오피스, 그리고 윈도우와 같은 OS 관련 단축키도 포함해서 말이다. 상급 개발자라고 하는것은 무언가 대단한 이치를 깨달은 사람이 아닌 별거 아닌 작은 습관들을 몸에 익힌 사람들일 뿐이다.



2. Command Line Interface

 상징적인 의미 이외에 현실적으로도 Command Line Interface(이하CLI)는 프로그래머가 보다 적극적이고 강렬하게 게을러지기 위해 꼭 필요한 중요한 도구이다. CLI는 동일한 작업의 반복 수행 뿐만 아니라 바로 위에서 언급한 마우스 사용의 억제에도 큰 도움이 된다.

대표적인 CLI화면인 Dos Prompt 


  CLI는 쉘 자체로도 다양한 작업이 가능하지만 AWK나 GREP와 같은 툴을 함께 사용한다면 엄청난 시너지 효과를 낼 수 있다는 사실도 잊지 말자. 윈도우의 경우 powershell을 사용한다면 DOS스타일의 bat보다 훨씬 다양한 작업이 가능하지만,  cygwin이나 unix utils를 이용한 유닉스 스타일의 쉘 작업을 익혀 둔다면,  윈도우 뿐만 아니라 유닉스, 리눅스는 물론이오 BSD를 기반으로 한 Mac OS에서도 요긴하게 써 먹을 수 있다.

 어찌 되었든, 하루에 두 번 이상 행하는 작업들은 무조건 CLI를 이용해 자동화 할 궁리를 하자!




3. 정규표현식

 부끄러운 이야기지만 필자 또한 정규 표현식을 제대로 다룰 수 있게 된 것은 비교적 최근의 일이다. 물론, 그 이전에도 정규표현식을 전혀 사용하지 않은 것은 아니지만 대부분 구글 검색에 의존해 완성된 식을 가져다가 파라메터를 바꿔서 쓰는 수준이었다. 변명을 하자면, 초보 개발자 시절 처음 접한 Perl 코드의 미칠듯한 정규표현식 해석 경험이 일종의 트라우마로 남아 있었던 듯 하다.

 이 정규표현식은 텍스트 데이터를 다루는데 있어서 엄청난 편의성을 제공한다. 특히 개발 도중 자주 직면하게 되는 복잡한 검색이나 치환 작업 들을 다루는데 있어서 대단히 편리한 도구이며, 게을러지기 위해서는 약간의 수고를 들여 꼭 익힐 필요가 있는 기술임에 의심의 여지가 없다.

 초보 개발자들에게는 다소 어려울 수 도 있지만 대부분의 이 바닥의 기술들이 그러하듯이 알고 나면 별거 아니다. 게다가 요즘에는 친절한 웹 튜토리얼들이 넘쳐난다!




4. 터미널 기반 텍스트 에디터

 이클립스나 IntelliJ, Sublime, Brackets와 같은 뛰어난 IDE가 넘처나는 시대이지만 아직까지 텍스트 편집기나 코딩 툴 로서 ViEditor(이하 Vim)이나 Emacs를 애용하는 개발자가 많이 있다. 텍스트 환경 위에서 움직이는 이러한 툴들은 위에서 언급한 키보드만 이용한 작업이라던지 터미널 상의 CLI인터페이스와 궁합이 좋기 때문이다.

 필자는 20년 가까이 vi를 사용해 오다가 얼마전에 Emacs로 넘어간 변절자 종 한 사람 이지만 양쪽 다 개발자에게 훌륭한 에디터 라고 생각한다. emacs를 사용한다 하더라도 vi는 대부분의 unix/bsd계열 os에서 기본 텍스트 에디터로 채용하고 있으므로 기초적인 사용법은 꼭 익혀 두도록 하자.




5. 구글 파워 서칭

 응? 이 양반이 초보라고 사람 무시하나? 아무리 초보 개발자라고 해도 구글 못 쓰겠냐고?
 아니다. 개발자에게는 개발자 다운 구글 사용법이 따로 있다.



 구글은 오늘날 프로그래머에게 있어서 문제 해결의 단서를 찾는 데에 절대 빼 놓을 수 없는 도구이지만 의외로 구글이 제공하는 강력한 검색 옵션 기능들을 제대로 사용하는 개발자는 많지 않다.

 속는 셈 치고 구글에서 제공하는 파워 Power Searching과 Advanced Power Searching 강의를 수강 해 보자. 아니 최소한 무슨 내용을 다루는지 만이라도 살펴보자. 단언컨데, 적은 노력으로 큰 편의를 제공할 것이다.





2014년 4월 6일 일요일

구글 자바 코딩 규약 업데이트

지난 3월 21일 구글에서 자바 코딩규약이 업데이트 되었다.

오라클에서 발표한 자바 코딩 규약이 널리 사용되고 있기는 하지만 너무 내용이 방대하고 예외를 적용할 수 있는 범위가 넓어 대부분의 기업이나 프로젝트에서는 이를 바탕으로 자신만의 룰을 만들어 사용하는 경우가 많다.

아직 코딩규약을 가지고 있지 않거나 기존 코딩규약에 대해 만족하지 못하고 있다면 구글의 코딩 규약을 참조하는것이 많은 도움이 될 것이다.

Google Java Style


이 규약은 강제력을 가진 룰 로서 구글 전체가 따르도록 되어 있어 아마도 룰을 따르지 않은 코드는 Checkstyle과 같은 자동화된 정적 코드 체커를 통해 에러로서 취급될 것이다.

이클립스를 사용하고 있다면 코드 포메터 임포트하여 편리하게 구글 코딩 스타일을 사용 할 수 있다.

Eclipse용 Google 스타일 코드 포메터


잘못된 네이밍과 관련해서 고민하지 말자.
이클립스를 포함해 대부분의 IDE는
리네임과 같은 편리한 리팩토링 기능을
기본적으로 지원한다.

이 규약은 여섯가지 영역으로 구성되어 있으며 각각의영역에서 다루는 내용은 다음과 같다.

  • 소스코드 기초 - 파일 네이밍, 파일 인코딩, 특수문자, Non-Ascii 문자
  • 소스코드 구조 -  저작권표시, 패키지 설명, 임포트 설명, 클래스 선언
  • 소스 포멧 - 괄호, 인덴트, 서술식, 줄당 문자수, 스페이스, 줄바꿈, 특정구문(Enum, 변수선언, 배열, 스위치문, 어노테이션, 커맨트, 변환자, 숫자)
  • 네이밍 - 패키지, 클래스, 매소드, 상수, 비상수, 파라메터, 지역변수, 타입변수, 대소문자사용
  • 프로그래밍 방법 - Override어노테이션, 예외처리, 정적 맴버변수,  종료자
  • Javadoc - 포멧, 요약단편, Javadoc이 필요한곳


몇가지 특이한 점을 꼽아보자면 다음과 같다.

  • 와일드 카드 임포트 사용 금지 - 이클립스 보급 이후로는 사실상 와일드카드 임포트는 찾아보기 어렵게 되었다.
  • 2스페이스 들여쓰기- 들여쓰기에 있어서 2스페이스냐 4스페이스냐는 프로그래밍 역사상 가장 오래된 논란거리중 하나인데, 어쨌든 구글은 2스페이스 인덴트를 택했다. 모니터가 크면 별 상관이 없지만 노트북으로 작업을 하는경우, 들여쓰기에 의해 코드가 한줄에 안보이게 된다면 은근히 짜증이 난다.
  • 줄당 문자수 - 80 또는 100 문자. 80문자까지 제약하는것은 역시 노트북으로 작업하는 이가 많은 구글의 문화적 특성인 듯 하다.
  • C스타일 배열 선언 사용 금지 - String[] args ○ , String args[] X
  • 스위치문 사용시엔 반드시 default구를 정의할것
  • 지시자의 표기는 다음과 같은 자바언어 사양상의 등장 순서를 지킨다
public protected private abstract static final transient volatile synchronized native strictfp
구글에서는 다른 언어들에 대해서도 코딩 스타일 표준을 가지고 있다.






2014년 1월 16일 목요일

주석(comment)을 달지 말아야 하는 이유


일전에 애자일 개발에서의 문서화 작업에 대한 블로깅에서도 밝힌바와 같이 도큐멘테이션은 프로젝트의 목적(납품물)이 아닌 커뮤니케이션을 위한 수단이 되어야 한다. 올바른 문서화을 위한 원칙을 다시한번 간략히 살펴보자.



정보의 중복 금지: 같은 내용을 여러군데 적지 말라. 쓸데없는 노력이 들어갈 뿐만 아니라 결국에는 서로 다른 내용을 지닌 문서/코드를 보게될 것이다. 

코드에 포함 가능한 정보는 코드에 포함하라: 동일한 내용이 여러 장소에 적힐 수 있다면 코드가 우선시 되어야 한다. 코드에 표현하기 어려운 정보라면 그 다음 순위는 유지모델이 될 것이다.

라이프 사이클을 구분하여 사용하라: 프로젝트 내내 지속적으로 유지해야만 하는 유지모델과 특정 단계에서만 구성원들의 의식 통일을 위해 사용하는 임시모델을 구분하여 사용한다. 아키텍처 정의나 ER다이어그램과 같은 문서는 프로젝트가 끝난 후라 할 지라도 유지보수를 위해 여전히 유용한 반면, 특정 기능 구현을 위한 시퀀스 다이어그램이나 클래스 다이어그램과 같은 임시 모델은 회의를 진행하면서 화이트보드에 적은 내용을 디지털사진으로 남기는 것 만으로도 충분한 경우가 많다. 

주석을 달지 말아야 하는 이유

코드에 주석을 달지 말아야 하는 이유는 정보의 중복을 피하기 위해서입니다. 주석을 열심히 달기 보다는 읽기쉬운 코드를 만든는데 집중하세요. 메소드 내의 처리를 단일 기능 단위로 분할 하고 하고 각종 네이밍에 주의를 기울이십시오. 프로그램 사양에 대한 기술은 코드의 주석보다는 테스트 케이스의 Javadoc에 기대하는 동작을 기술하세요. 이렇게 작성된 Javadoc은 그 자체로서 훌륭한 상세설계서가 됩니다. - 나가사토(나가사토씨는 필자와 같은 Mamezou소속의 애자일 컨설턴트 이며 Disciplined Agile의 일본어판 번역을 비롯해 다수의 기술서적을 번역하였다.)

필자는 사실 테스트케이스의 Javadoc조차도 최소한의 내용만을 적는것이 좋다고 생각한다. 테스트 코드도 실행코드와 마찬가지로 코드 자체의 가독성을 최대화 하는것에 집중하는것이 좋다고 생각하기 때문이다.

잘 작성된 주석은 프로그램의 가독성을 매우 향상시킬 수 있는 반면, 잘못 작성된 주석은 프로그램의 가독성을 해칠 수 있다. 
코드 컴플리트(스티브 맥코넬, 2005)

주석을 달지 않는 코딩 유형은 자바의 코어 라이브러리 소스 코드를 비롯해 대부분의 오픈소스 코드에서 쉽게 확인 할 수 있다.

예제1) 스프링 소스코드
     @Override  
     public void initialize(  
             Servlet servlet, ServletRequest request, ServletResponse response,  
             String errorPageURL, boolean needsSession, int bufferSize, boolean autoFlush) {  
         throw new UnsupportedOperationException("Use appropriate constructor");  
     }  
     @Override  
     public void release() {  
     }  
     @Override  
     public void setAttribute(String name, Object value) {  
         Assert.notNull(name, "Attribute name must not be null");  
         if (value != null) {  
             this.attributes.put(name, value);  
         }  
         else {  
             this.attributes.remove(name);  
         }  
     }  
     @Override  
     public void setAttribute(String name, Object value, int scope) {  
         Assert.notNull(name, "Attribute name must not be null");  
         switch (scope) {  
             case PAGE_SCOPE:  
                 setAttribute(name, value);  
                 break;  
             case REQUEST_SCOPE:  
                 this.request.setAttribute(name, value);  
                 break;  
             case SESSION_SCOPE:  
                 this.request.getSession().setAttribute(name, value);  
                 break;  
             case APPLICATION_SCOPE:  
                 this.servletContext.setAttribute(name, value);  
                 break;  
             default:  
                 throw new IllegalArgumentException("Invalid scope: " + scope);  
         }  
     }  

예제로 제시한 코드는 주석이 필요 없을정도로 간결하다. 이번엔 테스트코드를 살펴보자.

예제2) 테스트코드
 /**  
  * Unit tests for the {@code MockPageContext} class.  
  *  
  * @author Rick Evans  
  */  
 public final class MockPageContextTests extends TestCase {  
     public void testSetAttributeWithNoScopeUsesPageScope() throws Exception {  
         String key = "foo";  
         String value = "bar";  
         MockPageContext ctx = new MockPageContext();  
         ctx.setAttribute(key, value);  
         assertEquals(value, ctx.getAttribute(key, PageContext.PAGE_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.APPLICATION_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.REQUEST_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.SESSION_SCOPE));  
     }  
     public void testRemoveAttributeWithNoScopeSpecifiedRemovesValueFromAllScopes() throws Exception {  
         String key = "foo";  
         String value = "bar";  
         MockPageContext ctx = new MockPageContext();  
         ctx.setAttribute(key, value, PageContext.APPLICATION_SCOPE);  
         ctx.removeAttribute(key);  
         assertNull(ctx.getAttribute(key, PageContext.PAGE_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.APPLICATION_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.REQUEST_SCOPE));  
         assertNull(ctx.getAttribute(key, PageContext.SESSION_SCOPE));  
     }  
 }  

테스트 코드 역시 매우 간결한 모습을 띄고 있다.
코드의 가독석을 높이는 가장 좋은 방법은 코드를 심플하게 유지 하면서 네이밍, 특히 변수의 네이밍에 신경을 써 주는것이 효과적이다.

변수명과 네이밍에 대한 내용은 코드 컴플리트에서 더할나위 없이 훌륭하게 다루어지고 있으므로 아직 읽어보지 않은 분이라면 꼭 읽어들 것을 추천한다.

2013년 5월 7일 화요일

자바 디컴파일 솔루션 소개

오픈소스가 주류를 차지하는 오늘날에도 자바 라이브러리 (jar) 파일에서 자바 소스를 추출해 내야 하는 경우가 종종 생기곤 한다. 이러한 경우 이 글이 도움이 될 수 있을 것이다.

1. Jar 파일 갯수가 적을 경우
JD-GUI
단독으로 동작하는 어플리케이션으로 어노테이션등 자바 5 이후의 소스에 대해서도 디컴파일을 가능하게 해준다. JAR 파일 단위의 디컴파일을 지원하며 디컴파일 된 소스는 패키지 구조 그대로 폴더에 저장된다. 디컴파일 하고자 하는 jar 파일이 적을경우 대단히 훌륭한 솔루션 이지만 jar파일이 수백개에 이른다던지 하는 경우 커맨드라인 인터페이스를 지원하지 않아 일일이 GUI를 통해 디컴파일을 해야만 하는 번거로움이 있다.

JD-Eclipse (Eclipse Plugin)
이클립스의 경우 JD-Eclipse를 추천한다. jadclipse도 같은 기능을 하는 플러그 인이기는 하나 기능적으로 최근까지 꾸준히 업데이트를 해 오고 있는 JD-Eclipse가 보다 나은 선택이 되리라 본다. (jadclipse는 2009년11월 업데이트를 마지막으로 개발이 멈춰있는 상태이다.)

2. Jar 파일 갯수가 대단히 많을경우
이 포스트를 작성하는 2013년 5월 현재. Java Decompiler 프로젝트에서 아직까지 커맨드라인 인터페이스를 제공하지 않는 관계로 수백개에 이르는 Jar파일을 디컴파일 해야 하는 경우에 의지력을 시험받는 경우가 생겨난다. 만약 자신의 인내심의 한계를 넘어가는 객수의 jar 파일들을 디컴파일 해야 하는 경우 다음과 같은 방법을 사용해 일괄적으로 디컴파일이 가능하다.
※단, 이 경우 제약이 있는데, jad 디컴파일러 자체가 워낙에 오래된 디컴파일러 이다 보니 어노테이션 같은 자바 5 이후의 문법에 대해서 제대로된 디컴파일이 되지 않는다는 점 을 주의해야 한다.

준비물
jad
jadretro
cygwin (리눅스나 유닉스의 경우 필요 없음. 위도우 쉘이나 파워 쉘을 사용하고자 하는 경우는 각자의 환경에 맞게 스크립트를 수정하여 사용할 것.)

①디컴파일 하고자 하는 jar파일들을 한자리에 모은다.
②7zip과 같은 압축 관리 툴을 이용해 jar 파일들을 각각의 파일명으로 된 폴더 아래 압축을 풀어낸다.
③java 5 이후의 컴파일러로 컴파일된 class파일들의 경우 jadretro를 이용해 jad가 디컴파일 가능한 형태의 바이너리 파일로 변환시켜 준다.
(for f in `find [class파일 저장 폴더] -name '*.class'`;do jadretro $f;done)
④폴더명을 jad컴파일러로 넘겨주어 디컴파일을 실행
(for f in `ls -1 [class파일 저장 폴더]`;do `jad -o -r -sjava -d[소스파일 저장 폴더]/$f/ tmp/$f/**/*.class` ;done)