개발자노트2008/01/25 19:21
우분투 리눅스에서 public key를 이용하여 ssh로 원격 서버에 접속할 때 상당히 느리다는 느낌을 받았는데 솔루션을 찾았습니다.

ssh -v 옵션으로 접속할 때 뭐하는지 살펴보니 다음과 같은 메시지가 나오고 "GSS failure"라고 나오는 부분에서 반복적으로 몇초간 멈춤 현상이 발생하는 것을 발견했습니다.

debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,gssapi-with-mic
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure.  Minor code may provide more information
No credentials cache found
debug1: Unspecified GSS failure.  Minor code may provide more information
No credentials cache found
debug1: Unspecified GSS failure.  Minor code may provide more information
debug1: Next authentication method: publickey

GSS API를 이용하여 접근 시도를 할 때 나오는 메시지라고 GSS를 사용하지 않도록 변경하면 public key로만 인증을 하게 되어 서버에 빠르게 접속을 할 수 있게 됩니다.

GSS를 사용하지 않기 위해서는 /etc/ssh/ssh_config에서 GSSAPIAuthentication 부분을 찾아 주석을 풀어주고 다음과 같이 no 값을 주면 됩니다.

#   HostbasedAuthentication no
GSSAPIAuthentication no
#   GSSAPIDelegateCredentials no
#   GSSAPIKeyExchange no

이렇게 바꿔주니 대략 접속하는데 15초 걸리던 것이 zero wait으로 바뀌더군요.

Posted by 앤디군
개발자노트2007/12/27 19:25
10 characteristics of a bad developer
10 characteristics of a great developer

 훌륭한 개발자의 10가지 특성, 나쁜 개발자의 10가지 특성에 관한 개인적인 의견을 써놓은 흥미로운 글들이 있어서 소개하고자 합니다. 글쓴이가 생각한 개인적인 의견이기 때문에 가치관에 따라서 동의하기 힘든 내용이 있을 수도 있는데 개발자라면 재미삼아서 어떤 점들이 자기한테 해당되는지 알아보는 것도 재미있을 것 같습니다.

훌륭한 개발자의 10가지 특성
 1. 커뮤니케이션에 능하다. 말을 잘해서 말로 때운다는 의미가 아니고 자기 의견을 정확히 전달할 줄 아는 사람.
 2. 항상 개선을 하기 위해 노력한다.
 3. 문제를 지적할 때에는 솔루션도 함께 제시한다.
 4. 부탁이나 질문에 대해서는 신중하고 긍정적으로 대처.
 5. 자신의 코드에 대해서 비판적인 시각으로 항상 개선의 여지를 찾는다.
 6. 모든 코드들을 중요시하고 쓸데없는 코드를 만들어내지 않는다.
 7. 무언가에 대해 제대로 알고 있음.
 8. 항상 새로운 지식을 추구한다.
 9. 주변 사람들이 자기계발에 도움을 준다.
 10. 책임감

나쁜 개발자의 10가지 특성
 1. 자아가 강해서 팀이나 동료의 성공보다는 자신의 성공을 원한다.
 2. 지식 공유를 하지 않는다.
 3. 자신의 코드에 대한 비판을 허용하지 않는다.
 4. 항상 잘못한게 없다. --> (반어법. 잘못해놓고 잘못하지 않았다고 우기는 경우를 말하는 것 같음)
 5. 공격이 최선의 방어다. 다른 사람이 자신을 공격하기 전에 먼저 공격한다.
 6. 자신만의 스타일로 코드를 작성한다. 어떤 표준 스타일 보다도 자신의 스타일이 우선.
 7. 유리한 상황만 찾아다닌다.
 8. 방관.
 9. 뒤에서 궁시렁 거리기.
 10. 좋지 않은 결과물에 대해 자신의 능력이 모자란다는 얘기 대신 단지 신경을 좀 덜 썼을 뿐이라고 한다.

 공감가는 내용입니다. 경험상으로는 훌륭한 개발자가 될 수 있는 특성과 나쁜 개발자가 될 수 있는 특성을 섞어서 가지고 있는 경우가 대부분인 것 같습니다. 훌륭한 개발자의 특성을 보다 많이 가지면 훌륭한 개발자쪽에 가까워지는 것이고 나쁜 개발자의 특성을 많이 가지게 되면 그 반대가 되겠죠.
 
Posted by 앤디군
개발자노트2006/02/27 09:42

Tips for using Eclipse effectively

Posted by 앤디군
개발자노트2006/01/18 23:15
Things That Newcomers to Ruby Should Know에서 발췌한 내용들이다.


1. ruby를 실행할 때 -w 옵션을 주어 실행하면 실행시 발생하는 경고(warning)메시지를 볼 수 있다. 환경 변수(RUBYOPT)를 설정하여 ruby interpreter에 옵션을 전달할 수 있다.

2. irb라는 ruby interactive shell이 있으므로 디버깅이나 테스트 용으로 사용하면 편리하다.

3. ruby관련 문서는 ri를 이용하면 쉽게 볼 수 있다.
ri File # File object ri IO.open # IO.open method

4. 문서에서 "Klass#method"로 표기된 method는 instance method이고 "Klass.method"로 표기된 것은 class method이다. 이것은 단순히 표기법일 뿐이지 ruby syntax는 아니므로 혼동하면 안된다.

5. String#[Fixnum]은 문자열의 지정된 위치에 있는 ascii값을 반환하지 문자 그 자체를 반환하지 않는다. 예를 들어 "hello"의 두번째 문자인 "e"를 출력하기 위해 "hello"[1]과 같은 ruby expression은 "e"를 반환하지 않고 "e"의 ascii값인 101을 반환하게 된다. ascii값이 아닌 문자 자체를 반환 받고 싶다면 위치 인덱스 뿐 아니라 길이도 함께 주어야한다. 또는 ascii값을 문자로 바꾸는 Fixnum#chr 을 이용해도 된다.

  • "hello"[1] ==> 101

  • "hello"[1, 1] ==> "e"

  • "hello"[1].chr ==> "e"

  • ?e ==> 101 # 해당 문자의 ascii값을 구함.


6. Array.new(2, Hash.new)는 두개의 동일한 Hash object에 대한 reference를 두개 가지고 있는 배열을 만든다. 서로 다른 Hash object를 포함하고 있는 배열을 만들고 싶다면 map이나 collect method를 사용하면 된다.
arr = (1..2).map {Hash.new}

7. mutable(내용이 변할 수 있는) 객체를 해쉬의 키로 사용했다면 키가 변할 경우 해쉬 키의 인덱스를 재배치해야만 바뀐 키로 데이터를 찾을 수 있다.
s = "mutable"
arr = [s]
hsh = { arr => "object" }
s.upcase!
p hsh[arr] # nil
hsh.rehash
p hsh[arr] # "object"

8. file에서 데이터를 읽어서 숫자로 처리를 하려면 .to_i, .to_f method로 정수 또는 실수로 변환을 해야한다.

9. ruby에는 ++, --와 같은 increment, decrement operator가 없다. i++과 같은 것은 parse error가 발생하고 ++i와 같은 것은 무의미한 operation이다. ++ 두개는 양수에 양수라는 의미이기 때문이다. 마찬가지로 --i 역시 음수의 음수는 다시 양수 이므로 그냥 i가 된다. 증가, 감소를 하려면 i += 1, i -= 1을 이용하면 된다.

10. local변수와 블럭 내에서의 local변수가 같이 사용될 때 주의해야한다. 블럭 내의 파라메터로 전달되는 local변수와 같은 이름의 local변수가 블럭이 선언되기 전에 사용되었고 이름이 같다면 블럭 내에 전달된 local변수는 바깥 쪽에 선언된 local변수를 override하게 된다.
11. ruby에서는 logical operator가 동일한 두 개의 세트가 존재한다. [!, &&, ||]는 [not, and, or]와 같다. 주의할 점은 연산자 우선 순위인데 [!, &&, ||]는 [=, %=, ~=, /=,...)등보다 우선 순위가 높은 반면 [not, and, or]는 우선 순위가 낮다.
a = 'test'
b = nil
both = a && b # both == nil ----> both = (a && b)
both = a and b # both == 'test' ---> (both = a) and b
both = (a and b) # both == nil

12. 다음과 같은 문장이 있을 때
case obj
when obj_1
when obj_k

여기에서 비교를 위해서 === operator를 사용하게 된다. 이 경우 비교 순서는 obj_1 === obj 또는 obj_k === obj가 된다. obj === obj_1과 같은 순서로 비교 되지 않는다. 비교 연산자의 순서가 중요한 이유는 ===가 operator가 아니고 method이기 때문이고 객체에 따라서 다르게 작동할 수 있기 때문이다. obj_1 === obj 는 obj_1.===(obj) 와 같다. 즉 ===는 operator가 아니고 method이름이다. Module이나 Class에 정의된 ===는 비교 대상이 되는 객체가 같은 종류의 클래스 또는 상위 클래스 인지를 비교한다. Regexp에서 ===는 =~ 와 같다. Range에서의 ===는 범위 내에 포함이 되었는지를 알려준다.

13. method호출 시 ( 앞에 white space를 주지 않아야 한다. $VERBOSE == true인 경우에 경고 메시지가 나온다.

14. .(dot)은 가장 우선 순위가 높은 operator이다. 그래서 1.e6은 Fixnum타입인 1에 e6라는 method를 실행하는 것과 같다. 원하는 결과를 얻으려면 1.0e6와 같이 해야한다

15. "o..k"는 Range객체를 나타내지만 "[o..k]"은 Array객체를 나타낸다.

16. Ruby에서는 오직 nil과 false만이 false로 간주된다. 0 또는 "", '', [], {} 등은 모두 true이다.

17. Ruby에서 = operator는 객체에 대한 reference를 복사하는 것이다. a += b는 실제로 a = a + b로 간주되어 처리된다. (a += b는 a의 값에 b를 직접 더하는 것처럼 보이지만 실제로는 따로 계산을 한 뒤 a에 재할당을 한다는 것임) 이와 같이 ruby에서는 어떤 operation이 객체를 직접 변화시키는지 변화시키지 않는지 주의해야한다. (mutable인지 immutable인지 주의해야한다는 얘기임. ruby에서는 method이름 뒤에 !가 붙는 것들이 있는데 이 convention으로 mutable operation인지 immutable opeation인지 알 수 있다. !가 붙으면 mutable operation)
예를 들어 String객체에 다른 문자열을 더하는 operation으로 '< <' 와 '+='가 있다. 속도의 차이로 본다면 '<<'쪽이 '+='보다 빠르다. 왜냐하면 '<<'는 원본 문자열에 직접 다른 문자열을 더하는 것이고 '+='는 숫자 연산에서와 마찬가지로 '+'로 문자열을 더한 후 새로 생성된 문자열을 다시 할당하는 것이기 때문이다.

18. Ruby에서는 객체를 deep copy하는 방법이 없다. Deep copy를 하고 싶다면 marshaling/unmarshaling을 이용하면 된다.

19. Class변수는 클래스 계층을 따라 공유 된다. Child class에게도 공유가 되고 instance화된 객체들에게도 모두 공유가 된다. 하지만 하나의 예외가 있는데 class변수가 하위 class에 의해 초기화가 된 경우에는 공유되지 않고 별도의 변수처럼 작동하게 된다.
class Base
def initialize; @@var = 'base'; end
def base_set_var; @@var = 'base'; end
def base_print_var; puts @@var; end
endclass Derived < Base
def initialize; super; @@var = 'derived'; end # notice
def derived_set_var; @@var = 'derived'; end
def derived_print_var; puts @@var; end
end

d = Derived.new
d.base_set_var; d.derived_print_var # -> 'base'
d.base_print_var # -> 'base'
d.derived_set_var; d.derived_print_var # -> 'derived'
d.base_print_var # -> 'derived'

위의 소스를 보면 notice라고 된 부분에서 super를 호출하여 상위 클래스의 constructor가 먼저 실행되도록 하였다. 하지만 아래 소스를 보면 super를 호출하기 전에 @@var를 먼저 초기화를 했다. 출력되는 결과를 보면 알겠지만 아래와 같이 하위 클래스에서 먼저 클래스변수를 초기화한 경우에는 클래스 변수가 공유되지 않고 별도의 독립적인 영역을 가지게 된다.

class Base
def initialize;
@@var = 'base';
end
def base_set_var;
@@var = 'base';
end
def base_print_var;
puts @@var;
end
end

class Derived < Base
def initialize; @@var = 'derived'; super; end # changed
def derived_set_var; @@var = 'derived'; end
def derived_print_var; puts @@var; end
end

d = Derived.new
d.base_set_var; d.derived_print_var # -> 'derived'
d.base_print_var # -> 'base'
d.derived_set_var; d.derived_print_var # -> 'derived'
d.base_print_var # -> 'base'

20. \(backslash) 치환에 주의
str = 'a\b\c' # -> a\b\c
puts str.gsub(/\\/,'\\\\') # -> a\b\c
puts str.gsub(/\\/,'\\\\\\') # -> a\\b\\c
puts str.gsub(/\\/,'\\\\\\\\') # -> a\\b\\c
puts str.gsub(/\\/) { '\\\\' } # -> a\\b\\c
puts str.gsub(/\\/, '\&\&') # -> a\\b\\c

Posted by 앤디군
개발자노트2005/11/29 10:58
WebWork: WebWork joining Struts

Opensymphonywebworkapache strutsStruts Ti로 합쳐진다고 한다. Struts는 훌륭한 사용자 커뮤니티를 가졌고 webwork는 훌륭한 기능을 갖췄다는 평을 가지고 있는데 이 두가지가 합쳐져 어떠한 모습으로 나타날지 궁금하다.

가장 완성도 높은 MVC framework이라고 생각하는 ruby on rails에 필적하는 java MVC framework이 나올 것인가???
Posted by 앤디군
개발자노트2005/11/21 10:16
JS/UIX - Terminal

요즘 참 신기한 것들 많아요..

덤으로 anyterm
Posted by 앤디군
개발자노트2005/11/16 23:31
DHT(Distributed Hash Table)이란 이름에서 알 수 있듯이 시스템 내의 각 노드(node)들이 키 셋을 나누어 가지고 있는 분산 시스템을 말한다. DHT시스템 외부에서 보면 일반 해쉬 테이블과 다를 게 없지만 일반적인 해쉬 테이블과 다른 특성을 가지고 있다.

특성
1. Decentrialisation : DHT 시스템 전체를 중앙에서 관리하는 조직이 없다.
2. Scalability : DHT를 이루고 있는 노드 수에 영향을 받지 않고 확장할 수 있다.
3. Fault tolerance : DHT 시스템 내부에 노드가 추가되거나 없어지거나 오동작을 하더라도 DHT시스템 전체의 기능에 영향을 끼치지 않는다.

기존 P2P솔루션은 Napster와 같이 중앙집중관리 방식과 Gnutella와 같이 주변 노드들을 활용하는 완전히 분산된 네트워크를 구성하는 방식이 있다. P2P네트워크를 중앙에서 컨트롤할 경우에 네트웍 이용효율은 좋아지겠지만 컨트롤이 중앙에 모여있기 때문에 중앙 관리 시스템이 취약점이 될 수 있다. Peer에 의지하는 방식은 중앙 집중 조직이 없어서 뚜렸한 취약점은 없지만 네트웍을 비효율적으로 사용한다는 문제가 있다. DHT는 structured key based routing이라는 방법으로 위와 같은 P2P시스템의 약점을 극복 했다.

DHT는 크게 Keyspace partitioning, Overlay network의 두부분으로 나뉘는데 해쉬의 키 집합들을 DHT시스템 내부의 각 노드에 분산(keyspace partitioning)시키고 DHT의 엔트리 포인트에 상관없이 키의 위치를 찾아갈 수 있도록 라우팅하는 알고리즘을 이용해서 DHT시스템 내부의 네트워크(overlay network)를 떠돌며 목적지를 찾아가게 된다. 이게 바로 structured key based routing인데 쉽게 얘기하자면 해쉬 테이블 내부의 버킷(bucket)을 그룹으로 묶고 그룹 사이를 링크로 연결하여 자기가 원하는 정보가 있는 그룹을 찾아갈 수 있도록 해주는 것이다. 외부에서 보면 해쉬처럼 보이지만 내부에서 원하는 버킷을 찾아가는 방식은 기존의 해쉬와 다르다.
Posted by 앤디군
개발자노트2005/10/17 15:52
HTML의 img 태그에는 alt 속성이 있다. 종종 alt속성의 의미를 망각하고 tooltip 처럼 사용하는 경우가 있는데 이는 MSIE에서 alt에 지정된 텍스트를 tooltip 텍스트로도 보여주기 때문이다. 하지만 alt속성은 이미지를 보여줄 수 없는 lynxw3m과 같은 텍스트 브라우저에서 이미지 대신 보여주기 위한 텍스트일 뿐 tooltip용 메시지를 넣는 곳이 아니다.

Mozilla Web Author FAQ에서는 왜 모질라에서 alt속성을 tooltip으로 보여주지 않는지에 대한 이유를 적어놨다.
  • When the alternative text is shown in a tooltip, some authors write bad alt texts, because they intend the text as auxiliary tooltip text and not as a replacement for the image. (‘Bad’ in the sense that the textual alternative is less useful for people who don’t see the image.)

  • When the alternative text is shown in a tooltip, other authors don’t want to supply textual alternatives at all, because they don’t want tooltips to appear. (Again, making things harder for people who don’t see the image.)



요점은 주어진 기능은 목적에 맞게 쓰자는 것이다. tooltip 메시지를 지정하기 위한 속성은 따로 있다. title 속성이 바로 그것인데 title 속성은 브라우저, 좀 더 폭넓게 얘기하자면 유저에이전트(user agent)에 따라 다르게 보여질 수 있는데 일반적으로 이미지를 지원하는 브라우저라면 tooltip의 형태로 나타나게 되고 음성을 지원하는 브라우저라면 음성의 형태로 나타날 수 있다.

아마도 alt와 title에 들어갈 메시지가 동일한 경우도 있을 수 있다. 브라우저에서 이미지의 또 다른 표현 형태에 대해 신경을 많이 쓰지 못하면 대충 alternative text와 tooltip을 동일한 문구로 넣는 경우도 있을 수 있는데 그렇다 하더라도 alt속성은 그 나름대로 생겨난 이유가 있고 title속성 역시 나름대로 생겨난 이유가 있는 속성들!.. 그 목적에 맞게 각각 적어주자.
Posted by 앤디군
개발자노트2005/10/13 10:18
ruby가 깔끔하고 타 언어의 좋은 장점들만을 모아서 만들었다는 철학에 걸맞게 좋은 인상을 주고 있다. 하지만 다만 한가지 걸리는 것은 웹 개발시 production level에서도 사용할 수 있을 만한 성능을 내줄 수 있느냐 하는 것이다.
우선은 소프트웨어의 구조를 잘 정돈하고 profiling을 통해서 성능 개선을 하면 어느 정도는 만족하지 않을까....

ruby interpreter에는 profiler가 내장되어 있다. profiler library를 포함시키는 것 만으로 전체 프로그램 실행 결과에 대한 profiling 결과를 얻을 수 있는데 -r profiler 또는 source code에 require "profiler"를 추가하면 된다.

개인적으로는 소스를 고치지 않고 -r profiler 옵션을 붙여서 실행하는 것을 선호한다. 아무튼 profiling을 한 결과는 프로그램 실행 후 다음과 같이 출력이 된다.


% cumulative self self total
time seconds seconds calls ms/call ms/call name
38.18 1.26 1.26 1145 1.10 1.49 KeywordExtractor#goto_s
12.73 1.68 0.42 68 6.18 113.38 Array#each
12.42 2.09 0.41 2946 0.14 0.16 Hash#[]
4.24 2.23 0.14 1780 0.08 0.08 Fixnum#==
3.33 2.34 0.11 1641 0.07 0.07 NilClass#nil?


다른 profiler와 비슷한 출력 결과를 보여주는데 java의 profiler와 같이 thread stack도 같이 보여주면 좋을 것 같은데 아쉽게 그렇게 그 정도까지 보여주진 않는다. 하지만 이런 정보를 -r profiler 옵션 하나로 쉽게 볼 수 있다는게 어딘가..
Posted by 앤디군
TAG 루비, 성능
개발자노트2005/09/15 11:38
Ajaxian: IE 7 has XMLHttpRequest as native component. NOT ActiveX.

MSIE7에서 XMLHttpRequest가 ActiveX object가 아닌 native object로 바뀐다.원문에서 언급된건 ActiveX가 disable된 상태에서도 XMLHttpRequest를 사용할 수 있다는 것이지만 new XMLHttpRequest(); 와 같이 XMLHttpRequest를 생성할 수 있다는 얘기일 것이다.

어제 막 세미나에서 XMLHttpRequest는 브라우저에 따라 얻어오는 방법이 다르다고 얘기했었는데.. emoticon
 

Posted by 앤디군