2010-09-20

서평 - The Passionate Programmer

The Passionate Programmer에 대한 서평이다.

소프트웨어 개발자를 위한 처세술이다. 이 책은

  • 기술과 직업에 대한 방향을 설정(Choosing Your Market)하고
  • 실력을 배양(Investing in Your Product)하고
  • 실행(Executing)하고
  • 나를 알리(Marketing... Not Just for Suits)고
  • 반복적으로 꾸준히 노력(Maintaining Your Edge)하는

것 등을 다룬다.

특별한 것도 없고 특별하지 않은 것도 없지만 일반적인 처세술 책(읽어본 책이 많지 않아 짐작에 지나지 않지만)보다는 개발자를 염두한 것이기 때문에 읽어볼만하다.


저자가 제시한 가이드라인 중에 앞쪽에 나온 몇가지를 골라보았다.

  • 새롭고 전도유망(?)한 기술과 비즈니스 도메인에 대해서 관심을 갖는다.
  • 나보다 뛰어난 사람들과 일할 수 있는 환경을 찾는다.(Be the Worst)
  • 새로운 프로그래밍 언어를 배운다.(주로 사용하는 언어와 개념이 크게 다른 언어를 선택한다.)
  • 다양한 분야에 관심을 갖고(Be a generalist), 깊이 파고든다.(Be a Specialist)

Be a Specialist에 저자 생각을 인용한다.(51 페이지)

Too many of us seem to believe that specializing in something simply means not knowing about other things.

  • 특정 기술(자바, .NET, Rails 등) 자체에 과도하게 의존하지 않는다.
  • 스승을 찾고 스승이 된다.



많은 부분이 공자님 말씀이다...
 

2010-08-16

[링크] Invalid XML Character

UTF-8 인코딩을 준수하는 문자 중에도 XML에서는 유효하지 않은 문자가 있다. (CDATA 혹은 escape 처리해야하는 <, > 등과는 별개로)


아래 링크는 이 유효하지 않은 XML 문자를 제거하는 방법을 다룬 블로그 포스트이다.

Invalid XML Characters: when valid UTF8 does not mean valid XML

2010-08-08

HTML 텍스트 태그

단락을 구성하는 텍스트 중에서 특정 부분만을 다르게 표현해야 하는 경우가 있다. 이 때 의도와 결과(웹 브라우저에 표시되는 모습)를 구분하고 초점을 결과가 아닌 의도에 맞추어야 한다. 강조하기 위해서 진하게 표현하는 것일 뿐 진하게 표현하는 것 자체는 중요하지 않다.


XHTML에는 의도를 명시하기 위한 텍스트 태그와 표현을 위한 텍스트 태그가 있다.


의도를 명시하기 위한 태그는 다음과 같다.

  • abbr - 약어
  • acronym - 두문자어
  • cite - 인용 출처
  • code - 프로그램 소스 코드(컴퓨터 관련 문서와 매뉴얼에서 주로 사용)
  • dfn - 용어나 경구
  • em - 강조
  • kbd - 사용자가 (키보드로) 입력하는 명령어(컴퓨터 관련 문서와 매뉴얼에서 주로 사용)
  • q - 인용글
  • samp - 텍스트로 표시되는 프로그램 실행 결과(컴퓨터 관련 문서와 매뉴얼에서 주로 사용)
  • strong - 매우 강조
  • var - 변수(컴퓨터 관련 문서와 매뉴얼에서 주로 사용)


표현을 위한 텍스트 태그는 다음과 같다.


  • b - 진하게(bold)
  • i - 기울이기(italic)
  • big - 크게(larger)
  • small - 작게(smaller)
  • tt - 모노스페이스 폰트로 표시하기(monospaced, teletypewriter)
  • sup - 텍스트를 위에 기입하기(어깨글자, superscripted)
  • sub - 텍스트를 아래에 기입하기(subscripted)


sup와 sub 태그를 제외한 표현을 위한 텍스트 태그는 사용하지 않는 것을 권장한다.


XHTML에서 삭제된 표현을 위한 태그들도 있다.

  • blink - 텍스트 깜빡이기
  • strike - 가운데 줄 긋기
  • s - strike와 동일
  • u - 밑줄 긋기
  • basefont - 페이지 전체 글꼴 설정
  • font - 글꼴 설정

cite와 q

q 태그는 인용하는 내용 자체를 명시하는데 사용하고, cite 태그는 출처를 명시하는데 사용한다.

홍세화 기자는 한겨레 신문에 기고한 <cite>의식과 정서</cite> 칼럼에서 정운찬 전 총리에 대해 <q>애당초 그의 정서는 불관용으로 악착스런 이 정권에 어울리지 않았다. 그러나 그는 권좌의 길을 택했다. 후배와 제자들의 끈질긴 만류가 있었지만 소용없었다. 그에게서 학문적 심지로서는 유약한 대신 “우리가 나라를 이끄는 주역이다”라는 주장 뒤에 숨어 있는 권좌에 대한 친화력에서는 무척 강한 한국 사회 엘리트의 자화상을 확인한다는 것은 즐거운 일이 아니다.</q>라고 평가하고 있다.

abbr과 acronym

두 태그를 나타내는 단어 abbreviation과 acronym을 모두 약어로 번역하면 차이가 명확하지 않지만, acronym을 두문자로 번역하면 그 차이를 쉽게 알 수 있다. abbr 태그는 한단어를 줄여 쓴 경우에 사용하고, acronym은 여러 단어의 앞 글자만을 대문자로 이어 표기한 경우에 사용한다.

  • abbr - Jan.(January), Mr(Mister), Ltd.(Limited), ad(advertisement), exam(examination)
  • acronym - CEO(Chief Executive Officer), BBC(British Broadcasting Corporation), DOS(Disk Operating System)

2010-05-13

SAS

대학 때 통계 분석 패키지를 판매하는 회사로 SAS를 처음 알았다.

그러다가 예전 글에서 좋은 회사라고 들었다. 그때까지만 해도 독일 회사인줄 알았는데^^


한겨레 Insight 기사를 보니 부럽다.

2010-04-27

JUnit 이야기

JUnit에 대해서 새롭게 알게 된 사실들.


실행 시간을 기준으로 테스트 실패 여부를 판단할 수 있다.

@Test(timeout = 130)
public void something() {
    ...
}


Ignore Annotation으로 테스트가 실행되지 않도록 할 수 있다.

@Test
@Ignore
public void something() {
   ...
}


TestSetup 클래스로 전체 테스트에 대한 초기화를 수행할 수 있다.

동일한 테스트를 파라미터화해서 여러번 수행할 수 있다.

@RunWith(value = Parameterized.class)
public class SomeTest {

    @Parameters
    public static Collection<Some> getSomes() {
        return ...
    }

    public SomeTest(Some some) {
        ...
    }

    @Test
    ...
}



EasyMock과 JMock이라는 Mock 라이브러리가 있다.

Ant를 사용할 때 Ivy를 이용해서 라이브러리를 관리할 수 있다.


Winstone이라는 서블릿 엔진이 있다.

hamcrest 라이브러리로 assert 기능을 확장할 수 있다.

HtmlUnit, Selenium, HtmlUnit, JsUnit, Rhinounit, Jslint, jslint4java

Cobertura
라는 테스트 커버리지 툴이 있다.

2010-04-26

서평 - 웹 폼

웹 폼(Web Form)에 대한 Web Form Design: Filling in the BlanksForms that Work: Designing Web Forms for Usability에 대한 서평이다.


웹 폼에 대한 책을 쓸 생각을 하다니... 제한적인 소재 때문인지 두 책 모두 200페이지 정도로 읽기에 부담이 없다. 창조적이지는 않지만 애플리케이션을 개발하면서 한번쯤 고민하거나 해야할 내용들을 잘 정리해 두었다.

당연하게 생각되는 내용들이 많지만 그건 책을 읽었기 때문일 게다. 이 두 책은 애플리케이션을 개발하면서 당면할 소소한 문제들을 해결하기 위해 투자해야 하는 시간을 크게 줄여주는 미덕이 있다.


이 책은 같은 주제를 다루지만 차이가 있다.  첫번째 책은 How(구현이 아닌 디자인 측면에서)에, 두번째 책은 Why에 방점이 찍혀있다. 따라서 두 책을 모두 읽는 것이 도움이 될 듯 싶다.

2010-04-20

서평 - Effective UI

Effective UI에 대한 서평이다.

30 페이지는 정독하고 나머지는 그냥 큰 글자만 보는 수준에서 훌터봤다.


어쩌자고 책 제목을 그렇게 지웠을까? Effective JavaEffective C++ 등과 같은 명저 반열에 오르고 싶었던건가. UX를 하는 사람들이라서 네이밍 혹은 마케팅에 탁월한걸까? 그 탁월함이 글쓰기에 발휘되었다면 좋았을 것을...

물론 오해다. 저자들 다수가 일하는 회사 이름이 그럴 뿐이다.


책에 UI는 없다. UX도 없다. 이 단어들이 등장하지 않는 것은 아니다. 자주 등장하지만 이 책은 좋게 평가해도 소프트웨어 개발 방법론에 지나지 않는다. 재미없기로는 대기업 SI 방법론 매뉴얼과 우열을 가르기 쉽지 않다. 대기업 SI 방법론 매뉴얼은 간결하다는 미덕이라도 있다만 이 책은 그나마도 없다.

소프트웨어 개발 방법론이라면 이 책보다 월등히 좋은 책들이 많다는 점에서 이름 하나는 잘지었다.


자 그럼 Effective UI는 어디에 있는가?


2010-04-19

서평 - Modular Java: Creating Flexible Applications with OSGi and Spring

Modular Java: Creating Flexible Applications with OSGi and Spring에 대한 서평이다.

200 페이지가 조금 넘는 분량으로 OSGi 기반 웹 애플리케이션 개발 방법을 Step-by-Step으로 설명하고 있다.

소스코드, OSGi 설정 파일 내용, Maven(Pax Construct) 실행 결과 등이 1/3을 가까이 차지하니 내용은 많지 않다.

OSGi가 무엇인지, OSGi를 이용해서 웹 애플리케이션을 어떻게 개발해야 하는지를 파악하는데 부담없으면서 유용한 책이다.

부정적으로 본다면 다음 아마존 독자 서평에 동의한다.


스스로도 이클립스가 OSGi에 기반하고 있다는 정도로만 OSGi를 접하고 있었는데 이 책을 통해서 다음 내용들을 알 수 있었다.

  • OSGi를 구현한 플랫폼에는 Eclipse EquinoxApache Felix 등이 있다. 이 책에서는 주로 Equinox(뭐라고 발음해야 하는지^^)를 다룬다.

  • 모든 것이 모듈이다. 라이브러리도, 유틸리티나 모델(Bean이든 Domain 객체 등)도... 그리고 톰켓(혹은 Jetty)도 모듈이다.

  • Maven 기반 Pax Construct로 개발을 진행한다. EJB 만큼은 아니지만 소스코드보다 설정 파일이 많은 느낌이다. 이를 편리하게 해주는게 Pax Construct라는 도구이다.

  • Spring Dynamics Module로 OSGi 개발을 편리하게 진행할 수 있다(라고 쓰고 주장한다라고 읽는다). 잘 알지도 못하지만 여전히 Spring에는 정이 가지 않는다.


실패한 EJB보다는 여러가지 장점을 갖는다.

  • 모듈이 갖는 적절한 크기. EJB는 너무 작았다. 그래서 모듈이 아닌 컴포넌트라는 이름을 사용했겠지만...

  • SOA in JVM. 빌어먹을 Remote^^

  • 확장이 유연하다. Fragments를 통한 모듈 확장이 가능하다. Eclipse가 보여준 Extenion과 Extension Point를 이용한 확장이 이것이 단순한 마케팅 용어가 아님을 증명한다.

  • 버전 관리. 동일한 모듈의 다양한 버전이 공존할 수 있다.

  • 라이브러리나 공통 클래스(유틸리티, Bean, Domain 객체)를 모듈로 공유하는 방법이 명확하다.

2010-04-13

데이터 유형과 의도적 제한

프로그래밍 언어들은 다양한 데이터 유형을 제공한다. 가령 자바가 제공하는 데이터 유형은 다음과 같다.

  • byte
  • short
  • int
  • long
  • float
  • double
  • boolean
  • char
  • String

* java.lang 패키지에 있는 Wrapper 클래스를 고려하면 2배가 된다.

그런데 애플리케이션 개발에 쓰는 데이터 유형 숫자를 최소화하면 생산성이 높아지고 유지보수 비용이 감소하지 않을까?

정수를 표현할 때 short나 byte는 사용하지 않고 int와 long만 사용하거나 극단적으로 long만을 사용하면 어떨까?

실수도 float 대신에 double 만을 사용하고 모든 문자열은 String으로만 표현한다든가...

* 아주 극단적으로 모든 숫자를 double로 표현할 수도 있다.


예외적인 경우를 제외한다면 이런 결정이 CPU 성능이나 메모리 양에 미치는 영향도 감내가능하지 않을까?

일단 기본적으로는 다음 데이터 유형만을 사용해서 애플리케이션 개발을 하려고 한다.

  • int
  • long
  • double
  • boolean
  • String

* 정말 int, long은 사용하지 않고 double만을 사용하면 어떨까?

이런 결정은 관계형 데이터베이스 테이블 스키마에도 선순환적 영향을 미칠 것이다.

서평 - Even Faster Web Sites

Even Faster Web Sites에 대한 서평이다.

High Performance Web Sites를 쓴 저자(Steve Souders)가 쓴 책이다. 책 절반 정도는 다른 사람들이 썼다.

High Performance Web Sites 내용은 논란의 여지없이 준수해야 하는 가이드라인이다. 그런데 Even Faster Web Sites 내용을 접했을 때 든 생각은 이런 변태들이 있나였다. 좋게 말하면 프로와 아마추어의 차이가 느껴졌다고할까...


저자가 몸담았거나(야후) 몸담고있는 회사(구글)를 생각하면 이런 극단적인 접근과 고민들이 이해된다. 작은 사이트에서 1% 트래픽 절감은 그 효과가 미미하지만 저런 빅 회사에서는 어마어마한 비용 절감일테니깐.

어찌되었든 이 책에 있는 내용들은 실감나게 다가오지 않는다. 그러나 알고 있으면 언제가 필요할 때 무기가 되어줄 것 같다. 몇 가지 내용을 정리하면 다음과 같다.

  • 초기 화면 구성에 필요하지 않는 스크립트나 스타일쉬트는 늦게 로드한다. 이를 위한 방법들을 설명한다.
  • 웹 브라우저는 스크립트를 병렬적으로 다운로드하지 않고 순차적으로 다운로드한다. 이를 병렬적으로 다운로드할 수 있는 방법들을 설명한다.
  • 여러 이유로 Gzip이 지원되지 않는 경우에(웹 브라우저는 지원하지만) 이를 지원하는 방법을 설명한다.
  • 이미지 파일을 최적화하는 방법(메타 정보 제거와 같은)을 설명한다.
  • 문서 양이 많은 경우에(Gzip 등을 고려해서) 이를 순차적으로 Flush하는 방법을 설명한다.
  • iframe과 CSS Select가 웹 사이트 성능에 미치는 영향과 이를 최적화하는 방법들을 설명한다.
  • 자바스크립트 최적화 코딩 기법이나 Comet 등도 다루는데 내용이 충실하지는 않다.

2010-04-12

자바스크립트 - 문자열 앞뒤 여백 제거

Even Faster Web Sites를 보면 문자열 앞뒤 여백을 제거하는 자바스크립트 함수를 최적화하는 방법이 나온다.

먼저 가장 간단한 방법이다. 정규 표현식으로 문자열 앞뒤 여백을 제거한다.

function trim(text) {
    return text.replace(/^\s+|\s+$/g, "");
}


다음과 같이 정규 표현식에서 g 옵션을 제거하면 성능을 개선할 수 있다.

function trim(text) {
    return text.replace(/^\s+/, "").replace(/\s+$/, "");
}


문자열 뒤에 있는 여백을 정규 표현식을 사용하지 않고 처리하면 성능을 더욱 개선할 수 있다.

function trim(text) {
    text = text.replace(/^\s+/. "");
    for (var i = text.length - 1; i >= 0; i--) {
        if (/\S/.test(text.charAt(i))) {
            text = text.substring(0, i + 1);
            break;
        }
    }
    return text;
}


어떤 방법이 어떤 방법보다 항상 올바른 것은 아니다. 마지막 방법은 성능이라는 장점을 갖지만 변태들을 위한 방법일 수 있다. 첫번째 방법은 간결하지만 성능이 중요한 부분에 사용하기에는 적합하지 않다.


Prototype은 두번째 방법(String#strip)을 사용한다.

function strip() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
}



서평 - High Performance Web Sites

High Performance Web Sites에 대한 서평이다.

서버가 아닌 웹브라우저(클라이언트)에 초점을 맞추어서 웹 사이트 성능 최적화에 사용할 수 있는 방법들을 제시한다. 그 내용이 간결하고 실질적이며 매력적이다.

책일 읽는 동안 자연스럽게 요즘 개발하고 있는 애플리케이션에 어떻게 적용해야 할까하는 숙제들이 쌓여갔다.


1. HTTP 요청을 최소화한다.(Make Fewer HTTP Requests)

자바스크립트 파일과 CSS 파일을 한 두개로 병합한다. CSS Sprites로 여러 이미지 파일도 하나로 병합할 수 있다.


2. CDN을 사용한다.(Use a Content Delivery Network)

사용자와 서버가 지역적으로 분산되어 있는 경우에 이미지, 자바스크립트, CSS 등의 정적인 파일들을 CDN에 복제하여 사용한다. 동적인 애플리케이션을 분산하는 것은 어려운 일이지만 정적인 파일들을 분산하는 것은 상대적으로 어렵지 않으며 효과도 크다.


3. Expires 해더를 설정한다.(Add an Expires Header)

이미지 뿐만 아니라 자바스크립트, CSS 등을 웹 브라우저 캐싱 기능으로 제어한다. 변경시에 이를 반영하는 효과적인 방안도 함께 강구한다.
 

4. Gzip 컴포넌트(Gzip Components)

텍스트 데이터는 모두 Gzip으로 압축한다. 서버 CPU 사용률이 증가하는 단점이 있지만 데이터 전송량을 줄이는데 가장 효과적이다.


5. 스타일쉬트는 위에 놓는다.(Put Stylesheets at the Top)

CSS 파일이 다운로드된 후 화면 구성이 된다. 따라서 화면이 점진적으로 나타나도록 하려면 CSS 파일이 내용(html)보다 먼저 다운로드되어야 한다. 표준에서도 link 태그는 head 태그에서만 사용할 수 있다.


6. 스크립트는 아래에 놓는다.(Put Scripts at the Bottom)

스크립트를 다운로드하는 동안에는 다른 파일 다운로드는 이루어지지 않는다. 따라서 화면 구성과 직접적으로 연관이 없는 스크립트는 맨 마지막에 위치시킨다.


7. CSS Expressions 사용을 지양한다.(Avoid CSS Expressions)

매력적인 기술이지만 UI 이벤트가 필터링되지 않기 때문에 매우 민감하게 반복적으로 반응한다. 결국 성능에 부정적인 영향을 야기하기 때문에 사용하지 않는다.


8. 자바스크립트와 CSS를 별도 파일로 분리한다.(Make Javascript and CSS External)

여러 화면에서 공유된다면 당연히 자바 스크립트와 CSS를 별도 파일로 분리한다.


9. DNS 찾기를 줄인다.(Reduce DNS Lookups)

도메인 이름을 최소화한다. 주요 웹 브라우저에서는 2개의 도메인을 사용할 때 최적화된 처리를 한다. 따라서 정적인 파일들은 처리하는 도메인을 별도로 분리하여 사용하는 것을 권장한다.


10. 자바스크립트를 최소화한다.(Minify Javascript)

여백을 제거하거나 로컬 변수명을 최소화해서 자바스크립트 파일 크기를 줄인다. 그 방법으로 Minification과 Obfuscation을 설명한다.


11. 리다이렉트 사용을 지양한다.(Avoid Redirects)

요청을 최소화한다는 측면에서 리다이렉트 사용을 지양한다. 리다이렉트에 대한 대안들을 설명한다.


12. 중복된 스크립트를 제거한다.(Remove Duplicate Scripts)

자바스크립트 뿐만 아니라 중복된 모든 것을 제거한다.


13. ETags를 사용하지 않는다.(Configure ETags)

클러스터링 환경에서 문제가 될 가능성이 다분하고 다른 대안이 있기 때문에 가급적 사용하지 않는다.


14. ....(Make Ajax Cacheable)

Ajax라고 크게 다르지 않다. 위에서 언급한 내용들을 그대로 준수한다.




이 책에서 제안하는 방법은 개발자보다는 시스템 엔지니어를 대상으로 한다. 따라서 적은 프로그램 수정 혹은 아파치나 IIS 등의 웹 서버 설정 변경만으로 위의 내용 대부분을 적용할 수 있을 것 같다.

2010-04-11

AJAX와 뒤로 가기 버튼

AJAX 혹은 DHTML을 사용할 때 뒤로 가기 버튼을 구현하는 방법이다.

Prototype 라이브러리
를 사용했다.


var Executer = Class.create({
  start: function() {
    new PeriodicalExecuter(function(pe) {
      if (!document.location.hash) {
        return;
      }
      var hash = document.location.hash.replace("#", "");
      if (hash == Executer.hash) {
        return;
      }
      Executer.hash = hash;
      if (hash.startsWith("menu")) {
        Menus.click(hash.substring(5));
     } else if (hash.startsWith("link")) {
        ...
     }
    }, 0.5);
  },
  execute: function(category, id) {
    window.location.href = "#" + category + "/" + id;
  }
});

사용 방법은 다음과 같다.

// onload 등을 이용해서 페이지 초기화시에 Executer 객체를 생성한 후에 start 메소드를 호출한다.

executer = new Executer();
executer.start();

뒤로 가기 기능을 제공해야 하는 경우 다음과 같이 처리한다.
<a href="#" onclick="executer.execute('menu', server/database'); return false;" >...</a>


동작 방법은 단순한다. 사용자가 뒤로 가기 기능이 필요한 행위를 할 때마다 window.location.href를 이용해서 url에 (#고유값)를 붙여준다. 이 경우에 화면이 변경되지지 않지만 웹 브라우저 경로창 URL과 히스토리 정보는 변경된다.

* IE 6에서는 안된다고 함. 이 경우에는 iframe을 사용하는 방법이 있다고 함.

그리고 백그라운드에서 주기적으로 스케줄러(여기서는 PeriodicalExecuter를 사용했는데, setInterval과 동일하다.)가 동작하면서 document.location.hash 값을 체크하여 변경이 있으면 변경 내용에 맞는 작업을 수행해준다.

* 스케줄러 호출 주기가 짧기 때문에 사용자는 거의 실시간 반응하는 것으로 느끼게 된다.

결국 사용자가 뒤로 가기 버튼을 눌러도 실제 어떤 작업이 이루어지는 것은 아니고 document.location.hash 값만 변경될 뿐이다. 물론 스케줄러가 변경 값을 확인하여 필요한 작업을 수행하게 된다.

hash 값에 따른 처리 코드는 상황에 맞게 수정해 주어야 한다. 여기서는 category를 이용해서 범주를 구분했다.



다음 내용을 참고했다.

Fixing the Back Button and Enabling Bookmarking for AJAX Apps

* 파이어폭스 3.6.3에서만 테스트를 했다.

2010-04-01

Ant 이야기

아파치 Ant를 쓴지도 8년이 넘었지만 제대로 파악하지 않고 대충 아는 지식에만 의존했기 때문에 항상 결과물에 모자람을 느껴왔다.

그러다 지금하는 일의 완성도를 높여야 한다는 당위성에 Ant에 시간 투자해서 얻은 경험 중 중요한 몇 가지를 정리해봤다.

Ant 작성에도 프로그래밍과 유사한 원칙들이 적용된다.

  • 내용 이해가 쉬워야 한다.
  • 중복된 내용이 없어서 변경하기 쉬워야 한다.

이런 원칙을 염두하고 다음 방법들을 사용했다.


이름을 명확하게


빌드 파일, 속성, 태스크 등의 이름을 길더라도 명확하게 설정한다.

예를 들어 테스크 이름을 copy로 하기보다는 copy_lib_to_web과 같이 명확하게 한다.


빌드 파일을 여러 개로 분리해서 모듈화 한다.

OOAD에서 클래스를 쪼개는 것과 동일하다. import 태스크와 antcall 태스크로 각 모듈을 효과적으로 조합할 수 있다.


라이브러리 작성

여러 빌드 모듈에서 사용하는 것들을 별도 파일에 정의한다. path 정보와 함수 역할을 하는 태스크 등이 여기에 해당된다.

라이브러리 모듈을 잘 작성하면 Ant 파일 내용을 크게 줄일 수 있다.

library.xml

<project name="library">

    <property file="build.properties" prefix="dimdol." />

    <path id="path.web.lib">
        <fileset dir="./lib">
            <include name="commons-fileupload-1.2.1.jar" />
            <include name="commons-io-1.4.jar" />
            <include name="commons-lang-2.4.jar" />
        </fileset>
    </path>

    <target name="library.compile">
        <javac srcdir="${source}"
               destdir="${target}"
               classpathref="${classpath}"
               source="${dimdol.compile.option.source}"
               target="${dimdol.compile.option.target}"
               debug="${dimdol.compile.option.debug}"
               encoding="${dimdol.compile.option.encoding}" />
    </target>

</project>

build_base.xml

<project name="build base" default="default">

    <import file="library.xml" />

    <target name="default">
        <antcall target="library.package_jar">
            <param name="source" value="${dimdol.base.src}" />
            <param name="target" value="${dimdol.base.target}" />
            <param name="classpath" value="path.web.lib" />
            <param name="jar" value="${dimdol.base.jar}" />
        </antcall>
    </target>

</project>

build_crm.xml

<project name="build crm" default="default">

   <import file="library.xml" />

   <target name="default">
       <antcall target="library.package_jar">
           <param name="source" value="${dimdol.crm.src}" />
           <param name="target" value="${dimdol.crm.target}" />
           <param name="classpath" value="path.web.lib" />
           <param name="jar" value="${dimdol.crm.jar}" />
       </antcall>
   </target>

</project>


컴파일을 담당하는 library.package_jar 태스크와 컴파일에 필요한 클래스 패스를 정의한 path.web.lib 패스를 library.xml 파일에 정의하고 build_base.xml, build_crm.xml 파일은 이 파일을 import한다.

* include가 더 유연하지만 Ant 1.8 부터 사용할 수 있다.


property는 properties 파일에 설정한다.

properties 파일에서도 ${}를 통해서 내용을 최소화한다.

build.properties

source = ./source
target = ./target
jar = ./jar

base.src = ${source}/base
base.target = ${target}/base
base.jar = ${jar}/base.jar

crm.src = ${source}/crm
crm.target = ${target}/crm
crm.jar = ${jar}/crm.jar

그런데 이 내용을 Ant 파일에서 사용할 때는 다른 많은 property와 쉽게 구분하기 위해서 prefix를 붙여 사용한다.

<property file="build.properties" prefix="dimdol." />

따라서 실제 사용할 때는 다음과 같이 한다.

<antcall target="library.package_jar">
   <param name="source" value="${dimdol.base.src}" />
   <param name="target" value="${dimdol.base.target}" />
   <param name="classpath" value="path.web.lib" />
   <param name="jar" value="${dimdol.base.jar}" />
</antcall>


2010-03-31

OS 스크립트에서 변수 설정 여부 확인하기

윈도우 스크립트(bat) 파일에서는 다음과 같이 변수 설정 여부를 확인한다.

if "%STARTUP_PORT%" == "" SET STARTUP_PORT=8080
if "%SHUTDOWN_PORT%" == "" SET SHUTDOWN_PORT=8005


유닉스 혹은 리눅스(sh)에서는 다음과 같이 변수 설정 여부를 확인한다.

STARTUP_PORT="${STARTUP_PORT}"
SHUTDOWN_PORT="${SHUTDOWN_PORT}"

if [ "${STARTUP_PORT}" = "" ]
then
    STARTUP_PORT="8080"
fi

if [ "${SHUTDOWN_PORT}" = "" ]
then
    SHUTDOWN_PORT="8005"
fi


2010-03-24

SMS 길이 체크하기

오늘 웹에서 SMS 전송 모듈을 작성했다.

  • 메시지 박스는 textarea로 구현한다.
  • SMS는 최대 80 바이트까지만 전송할 수 있다.
  • 사용자가 메시지 박스에 텍스트를 입력하면 실시간으로 하단에 텍스트 바이트 크기를 보여준다.

HTML 구조는 다음과 같다.

<div>
    <textarea id="text" rows="4" cols="30"></textarea>
    <br/>
    <span id="length"></span>
</div>


그리고 onkeydown(up, press) 이벤트로 바이트 크기를 체크하려는데 파이어폭스에서는 한글 입력에 대해서는 이 이벤트가 발행하지 않았다 ㅠㅠ


어쩔 수 없이 스케줄러(setInterval)로 백그라운드에서 바이트 크기를 처리하기로 했다. 약간의 딜레이를 감수하면서...

Prototype을 사용했다. 코드는 단순하지만 Prototype에 익숙하지 않으면 이해하기 쉽지 않다;;


우선 문자열 바이트 크기를 체크하는 함수를 String 클래스에 추가했다.

Object.extend(String.prototype, {bytes: function() {
    var source = this;
    var result = 0;
    for (var i = 0; i < source.length; i++) {
        result += (source.charCodeAt(i) > 128) ? 2 : 1;
    }
    return result;
}});

  • 기존 클래스에 메소드를 추가할 수 있다는 것이 자바 스크립트와 같은 언어의 장점이다.
  • Object.extend는 Prototype이 제공하는 메소드이다.
  • bytes라는 이름으로 메소드를 추가했다.

그리고 LengthChecker 클래스를 다음과 같이 작성했다.

var LengthChecker = Class.create({
    initialize: function(target, handler) {
        this.target = $(target);
        this.handler = handler;
    },
    apply: function() {
      this.target.observe("focus", this.start.bind(this));
      this.target.observe("change", this.stop.bind(this));
      this.target.observe("keydown", this.callback.bind(this));
    },
    start: function() {
        this.executer = new PeriodicalExecuter(this.callback.bind(this), 1);
    },
    stop: function() {
        this.executer.stop();
        this.callback();
    },
    callback: function() {
        this.handler($F(this.target).bytes());
    }
});

  • apply 메소드에서 observe 메소드로 target에 foucs, change, keydown 이벤트를 등록했다. focus에서 스케줄러를 시작하고, change 메소드에서 스케줄러를 정지한다. 한글이 아닌 경우에는 문제가 없기 때문에 keydown 이벤트도 등록하였다.
  • Protoype이 제공하는 PeriodicalExecuter는 setInterval을 이용한 스케줄러이다.


사용 방법은 다음과 같다.

new LengthChecker("text", function(length) {$("length").update(length);}).apply();


LengthChecker 클래스 생성자의 파라미터는 다음과 같다.

  • target: 대상 textarea 요소(혹은 id)
  • handler: 주기적으로 호출되는 함수. 이 함수의 첫번째 파라미터는 target에 입력한 텍스트의 바이트 크기이다.
LengthChecker 객체를 생성한 후 apply 메소드를 호출하면 백그라운드에서 바이트 크기 체크 작업이 이루어진다.

  • Prototype 라이브러리 PeriodicalExecuter는 최소 1초 단위로 반복된다. 딜레이를 최소화하려면 setInterval 함수를 사용하야 한다.

2010-03-17

CSS 초기화

Sitepoint에 올라온 The Right Frame of Mind: Applying the Lessons of CSS Frameworks에서 중요한 정보를 얻었다.

CSS 전문가인 Eric Meyer가 제안한 것으로 웹 브라우저마다 다른 CSS 속성 값을 일정하게 초기화하는 방법이다.

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center, dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-size: 100%;
vertical-align: baseline;
background: transparent;
}

body {
line-height: 1;
}

ol, ul {
list-style: none;
}

blockquote, q {
quotes: none;
}

/* remember to define focus styles! */

:focus {
outline: 0;
}

/* remember to highlight inserts somehow! */

ins {
text-decoration: none;
}

del {
text-decoration: line-through;
}

/* tables still need 'cellspacing="0"' in the markup */

table {
border-collapse: collapse;
border-spacing: 0;
}


2010-03-15

text-decoration

text-decoration 속성으로 텍스트 위, 아래, 가운데에 줄을 그을 수 있다.




blink로 텍스트가 깜빡이는 효과를 표현할 수 있다.



선은 color 속성으로 지정한 색상으로 표시된다. 다음과 같은 방법으로 선 색상과 텍스트 색상을 다르게 가져갈 수 있다.


<span style="color: blue; text-decoration: underline;"><span style="color: red;">CSS</span></span>

결과는 다음과 같다.


동일한 텍스트에 두 개 이상의 효과를 주려면 여러 개의 CSS 속성 값을 동시에 설정하면 된다.



2010-03-11

JIRA에서 GMAIL을 SMTP 서버로 사용하기

JIRA(버전: 4.0.2, 톰켓을 포함한 배포판)에서 GMAIL을 SMTP 서버로 사용하는 방법이다.


JIRA_HOME/conf/server.xml 파일에 다음 내용을 추가한다.

<Resource name="mail/GmailSmtpServer"
  auth="Container"
  type="javax.mail.Session"
  mail.smtp.host="smtp.gmail.com"
  mail.smtp.port="465"
  mail.smtp.auth="true"
  mail.smtp.user="myusername@gmail.com"
  password="mypassword"
  mail.smtp.starttls.enable="true"
  mail.smtp.socketFactory.class="javax.net.ssl.SSLSocketFactory"
/>


그리고 JIRA_HOME/atlassian-jira/WEB-INF/lib 디렉토리에 있는 아래 파일을

  • mail-1.4.1.jar
  • activation-1.1.1.jar

JIRA_HOME/common/lib 디렉토리에 복사한다.


마지막으로 JIRA를 재시작한 후에 Administration | Global Settings | Mail Servers 메뉴에서 SMTP 메일 서버를 추가한다.

이 때 JNDI Location에 java:comp/env/mail/GmailSmtpServer를 입력하면 된다.





2010-03-09

PERSPECTIVE ON PERFORMANCE

Jon Bentley가 쓴 Programming Pearls 6장. PERSPECTIVE ON PERFORMANCE를 정리한 글이다.

책에서 제시한 성능 문제를 해결하는 접근 방법은 다음과 같다.


1. 문제 정의(Problem Definition)

어떤 형태의 문제든 올바르게 문제를 파악하는 것보다 중요한 것은 없다. 성능 문제도 예외일 수 없다.

2. 시스템 구조(System Structure)

모듈화. 큰 문제를 작은 문제로 잘 나누기

3. 알고리즘과 데이터 구조(Algorithm and Data Structure)

잘 쪼개진 작은 문제를 해결하는 도구

4. 코드 튜닝(Code Tuning)

코드 잘짜기. 구조가 아닌 미시적인 접근

5. 시스템 소프트웨어

돈으로 해결하기 혹은 구글링

6. 하드웨어

돈...


시스템 소프트웨어나 하드웨어도 돈만으론 개선되지 않는다. 무엇을 바꾸어야 하는지를 파악해야 돈을 올바르게 쓸 수 있기 때문이다.


그런데 다른 문제와 마찬가지로 성능 문제가 발생할 대상 자체를 제거하는 것이 최상이다.

The cheapest, fastest and most reliable components of a computer system are those that aren't there.

존재하지 않는다면 장애와 보안 헛점에서도 자유롭다.

2010-02-16

프로세스 그 시작 - 스크럼

이름은 들어봤다 수준에서 아주 조금... 몇 발자국만(이나) 앞으로 나간 느낌이다.

Agile 열풍이 휘몰아 치던 시절에 조금 들어 본 스크럼을 우리가 일하는 방법 가운데에 놓았다.

3명이지만 프로세스는 필요하다고 판단했다. CMM Level 5를 준수하는 프로세스는 우리가 지구에서 가장 큰 소프트웨어 회사가 되면(구글과 MS와 애플을 합친 정도) 당연히 사용할 생각이다.(물론 관심없다의 다른 표현이다)

소프트웨어 개발 뿐만 아니라 일반적인 일하는 방식을 잡아줄 필요성에 많은 Agile 방법론 중에서 스크럼을 선택했다. 실제로 회사 설립과 관련한 일들도 백로그로 관리하고 스프린트 태스크로 설정하여 처리했다. 심지어는 마우스와 원두 커피 구매까지...


스크럼을 파악하려고 여러 글들을 읽었는데 그 중 아래 글들이 도움이 되었다.


* 책은 읽지 못했고, 다른 글들은 조금 오래되었거나.. 별로 감흥이 없었다.

첫번째 글은 철학(철학은 시류를 타지 않고 오래간다)을 다루고 두번째 글은 초보자를 위한 스크럼 안내서 같은 역할을 한다.


그리고 도구를 찾았다. 포스트잇을 사용하는 건 조금 어색하고 부끄럽다.

처음에 구글 Doc 스프레드쉬트를 사용했다. Burndown 차트 표현도 가능했고 탭으로 스프린트를 나누어 관리할 수도 있어서 나쁘진 않았다.(엑셀을 생각하면 된다) 그러나 백로그를 체계적으로 관리하기가 쉽지 않았다.

구글 Doc으로는 백로그를 User Story 혹은 Use Case로 기술하기가 쉽지 않다.


스프린트 2까지는 구글 Doc을 사용하다 스프린트 3 중간에 Rally로 전환했는데(이 역시 미리 정해놓은 태스크였다) 스프린트 3 종료와 함께 다시 구글 Doc으로 돌아갔다.

선무당이 Rally를 잡은 격이나... Rally 좋지 않다.


다음은 스프린트 1 Burndown 차트이다.

2주 혹은 4주가 아닌 업무일 기준으로 10일을 스프린트 기간으로 잡았다. 하루 실제 업무 가능한 시간을 5시간으로 정했으니 3명이 한 스프린트에서 사용할 수 있는 시간은 150 시간이다. 하지만 아직 완전한 셋업이 되지 않아 100시간 조금 넘는 규모로 스프린트 태스크를 구성했다.


지금까지 적용 과정에서 얻은 스크럼에 대한 생각은 긍정적이다.

  • 길을 잃지 않게 해준다.
  • 프로세스 자체에 소요되는 시간이 부담이 되지 않는다.(구글 Doc과 Rally를 왔다 갔다 하면서 낭비한 시간을 제외하면)

반면 좀 어렵게 다가오는 점은 백로그에 대한 관리이다. Uncle Bob 지적처럼...

  • 어떻게 백로그를 체계적(계층적)으로 관리할 수 있을까?
  • 백로그와 스프린트 태스크 간의 상관 관계는?
  • 특정 스프린트에서 완료하지 못한 태스크를 어떻게 처리해야 하는가?


(저렴하면서) 구미에 맞는 도구가 없다는 것이 아쉽다. 시간이 나면 스크럼 도구도 고민해봐야겠다.

2010-02-12

에어론 체어(Aeron Chair)... 듀오백

조엘 블로그에서 처음 알았다. 죽이는 의자라는 걸...

에어론 체어

[출처: 여기]


사업을 시작하면서 하나 갖고 싶었다. 물론 내가 갖는다는 건 모두가 갖는 다는 뜻이다. 세명 뿐이다.


Guy KawasakiThe Art of the Start에서 폼(Form)이 아닌 기능(Function)이 중요하다며 에어론 체어를 폼의 대명사로 다루었지만...어쩌면 그가 개발자는 아니었기 때문일거다(물론 내 주관적인 생각).


꽤나 자주 목이 뻐근하고... 큰 무게를 짊어진 것 같은 느낌에 정형 외과에서 물리 치료를 받은 적도 많아 더욱 탐이 났다.


그러나 구매한 건 듀오백 Alpha-100M


[출처: 듀오백 사이트]

얼마나 좋은지는 모르겠다. 에어론 체어를 써보지 않았으니...

NHN이 돈이 많다는 걸 증명한 의자에 대한 자세한 이야기는...


사람들은 다양한 생각들을 가진다.

2010-02-11

좋은 소프트웨어

사업을 시작한 후에 때때로 엄습해오는 불확실성을 억누를 때 기대는 명제가 있다.

좋은(Good) 소프트웨어는 팔린다.


조엘이 블로그에 쓴 다음(Headcount) 글이 이 명제가 참 일 가능성을 한번 더 증명한다.


그렇다면 좋은 소프트웨어는?

  • 사용자가 쓰기에 적절하다. 기능과 성능 측면을 모두 고려해서...
  • 유지보수를 포한한 개발 비용이 감당 가능하다.

결국 둘이 아니라 하나다.

적은 비용을 투자해서 개발한 쓸만한 소프트웨어


물론 구글이나 애플이나 마이크로소프트라면 이렇게 보겠지만...

뻑가는 죽이는 거... 돈 걱정은 하지 말고


불행하게도 혹은 다행하게도 난 구글을 위해 일하지 않는다.

돈을 왕창 쓰는 거야 자신 있지만... 뻑가는 걸 만들 재주는 없다. 돈으로 뻑 가는 걸 만드는 건 아니다. 삼성을 보라구...


어찌되었든 두번째 조건은 만족하면서 망망대해를 향해 항해를 시작했다.

개발자는 둘이다. 쓸만한 노트북, 모니터, 책상, 좋은 의자... 기타 등등을 사는데 소요한 비용도 이전 회사에서 받은 월급에 한참 못 미친다. (일인 기준으로)


그럼 좋은 소프트웨어를 만들 확률은 벌써 50%...

좋은 소프트웨어를 만들면 성공할 확률은 80%... (그렇다 치자^^)


그럼 성공할 확률은 이미 40%... 수학보다 산수가 좋다. 믿거나 말거나...

2010-02-01

CRACKING THE OYSTER

Jon Bentley가 쓴 Programming Pearls 1장. CRACKING THE OYSTER를 정리한 글이다.

제시된 문제는 다음과 같다.

n(최대 10,000,000 개 이하)개의 0보다 큰 정수로 이루어진 파일이 있다. 동일한 값은 존재하지 않으며, 정수 이외의 데이터는 없다.

이 파일에 있는 정수들을 어떻게 정렬할 수 있을까?

  • 메모리는 최대 1 MB까지만 사용할 수 있다.
  • 하드 디스크는 충분히 사용할 수 있다.
  • 몇 분안에 실행이 완료되어야 한다.


디스크를 이용한 Merge Sort

Merge Sort는 다음을 참고한다. 이 문제를 해결하는데 적합한 알고리즘은 아니다.


Multipass Sort

정수를 7 바이트로 표시하면 1 MB 메모리에 약 143,000 개의 정수를 올려 놓을 수 있다.

1024 * 1024 / 7 = 약 149,796

정수를 32 비트로 표시하면 1 MB 메모리에 약 250,000 개의 정수를 올려 놓을 수 있다.

1024 * 1024 / (32 / 8) = 약 262,144

이 정보를 기초로 파일을 여러번 읽어 문제를 해결할 수 있다.

첫번째 읽을 때는 0에서 249,999 사이 정수만을 메모리에 올려 놓은 후에 정렬을 하여 결과를 파일에 쓴다. 이렇게 반복적으로 마지막에는 9,750,000에서 9,999,999 사이 정수만을 대상으로 이 작업을 수행한다.

반복적으로 40 차례 파일을 일으면 모든 정수를 정렬할 수 있다.

10,000,000 / 250,000 = 40


비트맵을 이용한 처리

정수 이외의 데이터는 없고, 중복된 값이 없다는 전제 조건을 이용하면 간단하게 비트맵으로 문제를 해결할 수 있다.

즉, 크기가 10,000,000인 비트 배열을 만들어서 특정 정수가 존재하면 다음과 같이 처리한다. 예를 들어, 13,223가 존재하면 다음과 같이 한다.

bit[13223] = 1;

* 1 MB 이상 메모리가 필요하다. 1 MB가 엄격한 제한 조건이라면 Twopass Sort와 함께 사용한다.


가상 코드는 다음과 같다.

/* phase 1: initialize set to empty */
for i = [0, n)
  bit[i] = 0
/* phase 2: insert present elements into the set */
for each i in the input file
  bit[i] = 1
/* phase 3: write sorted output */
for i = [0, n)
  if bit[i] == 1
    write i on the output file



비트맵을 이용한 해결 방법은 범용적이지는 않다. 즉 특정 문제를 해결하는데 적합하다. 그런데 특정 문제를 해결하는데는 탁월한 방법이다. 

문제를 해결하는데 가장 중요한 것은 문제를 이해하고 정의하는 것이다.
Careful analysis of a small problem can sometimes yield tremendous practical benefits.


2010-01-25

A SAMPLE PROBLEM

Jon Bentley가 쓴 Programming Pearls 12장. SAMPLE PROBLEM을 정리한 글이다.

문제


여론 조사 기관에서는 N 명의 사람 중에서 M 명의 사람을 무작위로 추출하여 설문 조사를 한다.

M < N


N 명의 사람엔 0부터 시작하는 일련번호가 부여되어 있다. N을 5라고 가정하면 다음과 같다.

0 강백호
1 서태웅
2 채치수
3 정대만
4 송태섭

M이 2라면 이 중 동일한 확률로 2명을 추출해야 한다.

이는 0에서 N 사이에서 M 개의 숫자를 동일한 확률로 무작위로 추출하는 것에 다름아니다.

* 이 문제를 해결하는데 다음 2 함수를 사용할 수 있다.

bigrand : m 혹은 n 보다도 클 수 있는 정수를 무작위로 반환한다.
randint(i, j) : i에서 j 사이에 포함되어 있는 정수를 무작위로 반환한다.


솔루션 1

select = m
remaining = n
for i = [0, n)
  if (bigrand() % remaining) < select
    print i
    select--
  remaining--

* 추출된 숫자는 m 보다 많을 수도 m 보다 적을 수도 없다. 강조한 부분을 주의 깊게 보면 이를 파악할 수 있다.

일련번호가 0인 강백호가 선택될 확률은 2 / 5이지만 이 후에 있는 사람들이 선택될 확률은 앞 결과에 영향을 받는다. 예를 들어 강백호가 선택되면 일련번호가 1인 서태웅이 선택될 확률은 1 / 4이고, 강백호가 선택되지 않으면 서태웅이 선택될 확률은 2 / 4이다.

그러나 전체적으로는 서태웅이 추출될 확률도 2 / 5이다.

서태웅이 추출될 확률
= 강백호가 추출될 확률 (2 / 5) * 1 / 4 + 강백호가 추출되지 않을 확률 (3 / 5) * 2 / 4
= 2 / 20 + 6 / 20
= 2 / 5

이를 C++로 구현하면 다음과 같다.

void genknuth(int m, int n)
{
  for (int i = 0; i < n; i++)
    if ((bigrand() % (n - i) < m) {
      cout << i << "\n";
      m--:
    }
}


솔루션 2

set에 난수를 담는 방법도 있다.

* set에는 동일한 값이 들어 갈 수 없다.

initialize set S to empty
size = 0
while size < m do
  t = bigrand() % n
  if t is not in S
    insert t into S
    size++
print the elements of  S in sorted order

C++ STL을 이용하여 구현하면 다음과 같다.

void gensets(int m, int n)
{
  set<int> S;
  while (S.size() < m)
    S.insert(bigrand() % n);
  set<int>::iterator i;
  for (i < S.begin(); i != S.end(); ++i)
    cout << *i << "\n";
}


솔루션 3

n 개 크기 배열을 만든 후에 이들의 위치를 무작위로 변경(swap)하고 처음 m 개를 선택하는 방법도 있다. 화투나 포카에서 카드를 섞는 것(shuffle)과 유사하다.

for i = [0, n)
  swap(i, randint(i, n - 1))


C++를 구현하면 다음과 같다.

void genshuf(int m, int n)
{
  int i, j;
  int *x = new int[n];
  for (i = 0;; i < n; i++)
    x[i] = i;
  for (i = 0; i < m; i++) {
    j = randint(i, n - 1);
    int t = x[i]; x[i] = x[j]; x[j] = t;
  }
  sort(x, x + m)
  for (i = 0; i < m; i++)
    cout << x[i] << "\n";
}

개념 코드와는 다르게 m개 까지만 swap한다. (Ashley Shepherd와 Alex Woronow)



기타

만약 n이 100만이고 m이 n - 10이라면 조금은 다르게 접근해야 한다. 이 경우에는 추출되지 않을 10개를 계산하는 것이 적합하다.



프로그래밍 혹은 문제 해결은 다음과 같이 진행된다.

  1. Understand the Perceived Problem
  2. Specify an Abstract Problem
  3. Explore the Design Space
  4. Implement One Solution
  5. Retrospect

2010-01-13

Putty에서 캐릭터 셋 고정

Putty에서 캐릭터 셋을 UTF-8로 변경해도 다시 접속하면 값이 초기화되는 문제가 있었다.

이를 해결하는 방법이다.

http://k.daum.net/qna/view.html?qid=3yKL8



결론은 계정 정보 자체를 저장해야 한다는 것이다... 직관적이지 못하다...

2010-01-12

Color...

00FF66과 같은 HEX 문자열로 java.awt.Color 객체를 만들어야 했다.

Color 클래스 생성자는 RGB 값만을 파라미터로 받으니 귀찮은 데이터 전환을 해야 하나 고민하다가... 다음 메소드를 이용하면 된다는 걸 알았다.

Color color = Color.decode("00FF66");

그런데 예외가 발생했다. 앞에 #을 붙여 주어야 했다.

Color color = Color.decode("#00FF66");


그런데 스택트레이스 덕분에

Exception in thread "main" java.lang.NumberFormatException: For input string: "0ff66"
    at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
    at java.lang.Integer.parseInt(Integer.java:458)
    at java.lang.Integer.valueOf(Integer.java:528)
    at java.lang.Integer.decode(Integer.java:958)
    at java.awt.Color.decode(Color.java:707)

실제로는 Integer 클래스의 decode 메소드를 사용하면 된다는 것도 알았다.


2010-01-07

이클립스에 static import 처리

이클립스에서 static import를 편리하게 사용하려면 다음 설정을 해준다.

1. Organize Import 처리

http://www.prever.co.kr/josh/?p=35

2. Code Assist 처리

http://blog.naver.com/kcufl/60094963610