04.IT Knowledge/SAS2007. 10. 17. 17:56
%macro exportToExcel(tname);
filename _temp_ "C:\Documents and Settings\Administrator\바탕 화면\Chart 문서정리\samples\&tname..xls";
ods noresults;
ods listing close;
ods html file=_temp_ rs=none style=minimal;
proc print data=&tname noobs;
run;
ods html close;
ods results;
ods listing;
filename _temp_;
dm "winexecfile ""C:\Documents and Settings\Administrator\바탕 화면\Chart 문서정리\samples\&tname..xls"" ";
%mend;

%exportToExcel(REPORT.Flex2_xxx);
Posted by 아주 오래된 미래
04.IT Knowledge/단상들2007. 10. 5. 01:28

 많은 분들이 많은 프로젝트를 수행하는 요즘.

 그동안 프로젝트를 수행하면서 다소 아쉽게 생각한 어떤 개발자들의 행태에 대해 몇자 적고,
이 글을 읽는 분들은 그런 행동을 자제하셔서 보다 상쾌한 프로젝트를 만들어 나가시기 바랍니다.

 다들 아시다시피, 프로젝트는 대부분 팀단위의 작업입니다.
 그렇기에 프로젝트를 위한 공간에서 여러명이 공동작업을 하게 됩니다.
 그런데, 이렇게 공동작업을 하다보면 본인은 아무렇지도 않게 생각하지만 주위 사람은 눈살을
찌푸리거나 상당히 괴로워하는 경우가 있습니다.
 그 동안 제가 느꼈던 괴로운 것들을 몇 가지 적어보겠습니다.

 1. 업무시간에 자신의 자리에서 사적인 통화하기 + 느닷없는 벨소리 + 책상을 부술듯한
  진동소리.

  - 갑작스런 전화소리에 다른 사람 심장마비 걸릴지 모른다는 것을 아는지.
    그리고, 날마다 꼬박꼬박 자신의 자리에서 가족/친구/이전직장 동료들과 통화를 하는 분들이
  존재하더군요.
    프로젝트 내내 그런 사람도 봤습니다.
    심지어는 밖에서 전화를 걸어서 자신의 자리에서 통화를 하더군요.
    음.....그 사람의 전화기를 확 부셔버리고 싶은 감정이....
    아무튼, 제가 극악하게 싫어하는 행동인데, 그 사람에게는 이런말을 해주고 싶더군요.
    이봐, 나는 당신의 사생활이 궁금하지 않다구!!!!
   
 2. 이어폰을 꼽고 허밍으로 따라 부르기.
  - 아.....뭐라 할 말이 없습니다.
    이 사람들에게도 한 마디 해주고 싶죠.
    어이~나는 당신의 노래실력이 전혀 궁금하지 않다구!!!!

 3. 음악을 들으며 발 구르기.
  - 음....사실 약간 당황입니다.
    뭐지??? 이 사람???
    나는 당신의 박자 감각이 궁금하지 않다구!!!!

 4. 하루종일 하품하기(+하품소리 곁들여서).
  - 그런 사람의 입을 그냥 콱!!!! 하고 싶은 심정입니다.

 5. 근무시간에 자신의 자리에서 엎어져 자기 또는 졸기.
  - 나름 전날 바뻣다는 핑계나, 밥먹고 일어나는 생리작용이라고 주장하는 사람.
    그리고, 졸릴 때는 10분간 자는 것이 오히려 집중이 된다.라는 말을 절대 신뢰하며,
  실천하는 사람.
    그러지 말고 어디 안보이는 곳에 가서 한 30분 자고 오란 말이야!!!

 6. 방귀 뀌기.
  - 생리현상이라고 강력 주장하는 사람.
    왜??? 그럼 한 번 X도 싸 보시지???

 7. 목이 칼칼하다고 카~악하는 소리를 내는 사람.
  - 그런 소리를 들을 때마다 속이 다 울렁거린다는 것을 아는지...
    정 목이 칼칼하면 나가서 속시원하게 실컷 하던가, 자리에 물을 떠다놓고 수시로 마시던가...

 계속하자면 몇 가지 더 있지만, 갈수록 좀 지저분한 것 같아서 그만 하겠습니다.
 여러사람이 같이 작업하는데 조금씩만 매너를 더 지켜주면, 조금은 더 즐거워질텐데....
하는 생각이 많이 듭니다.

Posted by 아주 오래된 미래
04.IT Knowledge/Adobe Flex2007. 9. 20. 00:56
1. 필요한 경우 component를 위해 skin을 사용할 수 있습니다.
2. ActionScript class 파일을 만듭니다.
  2.1 UIComponent나 대상클래스를 상속합니다.
  2.2 MXML에서 사용할 속성을 정의합니다.
  2.3 graphic이나 skin을 embed합니다.
  2.4 constructor를 구현합니다.
  2.5 UIComponent.createChildren() method를 구현합니다.
  2.6 UIComponent.commitProperties() method를 구현합니다.
  2.7 UIComponent.measure() method를 구현합니다.
  2.8 UIComponent.layoutChrome() method를 구현합니다.
  2.9 UIComponent.updateDisplayList() method를 구현합니다.
  2.10 properties, methods, styles, events, and metadata 등을 추가합니다.
3. 파일을 배포합니다.
Posted by 아주 오래된 미래
04.IT Knowledge/Adobe Flex2007. 9. 19. 12:42
 Component의 lifetime동안 작성한 Application에서 Component의 이런저런 속성을 변경하는
경우가 있습니다.
 .....<< 예시 시나리오 생략 >> ...

 Flex는 component들의 속성변경등에 대해 invalidatioin 메커니즘을 사용합니다.
 Component변경에 대해 Flex에 변경을 알리기 위해서는 component의 commitProperties, measure, layoutChrome, 또는 updateDisplayList method를 사용해야 합니다.
 - invalidateProperties() : 다음의 screen update에 commitProperties가 호출되도록
                                Mark합니다.
 - invalidateSize() : 다음의 screen update에 measure가 호출되도록 Mark합니다.
 - invalidateDisplayList() : 다음의 screen update에 layoutChrome와
                        updateDisplayList가 호출되도록 Mark합니다.


 Component가 invalidation method를 호출하면, component가 update되어야 함을 Flex에 전달합니다.
 여러 component가 invalidation method를 호출하면, Flex는 다음 screen update 모두 함께 반영
되도록 처리합니다.

 일반적으로 component 사용자들은 invalidatioin method를 직접 호출하지는 않지만, setter
method의 사용등으로 내부적으로 호출됩니다.

 
Posted by 아주 오래된 미래
04.IT Knowledge/Adobe Flex2007. 9. 19. 09:43
 Flex2 help에 있는 내용을 일부 발췌하였습니다.
 요즘 Chart renderring에 관심이 있어서 내부적으로 method call하는 방식을 찾다가
발견했네요.


 Flex2에서 component를 아래와 같이 생성할 경우 다음의 내부적인 method가 실행됩니다.
var btnXX:Button = new Button();
btnXX.label = "확인";
boxContainer.addChild(btnXX);

1. 상위 컨테이너를 component의 parent로 등록합니다.
2. component의 style 설정을 계산합니다.
3. component에 preinitialize event를 발생시킵니다.
4. component의 createChildren method를 호출합니다.
5. invalidateProperties, invalidateSize와 invalidateDisplayList
 method가 9번 항목의 render 이벤트가 수행되는 동안 commitProperties, measure또는
 updateDisplayList method에 연결되어 수행됩니다.(??)
 -- 사용자가 width, height를 지정하는 경우에는 measure() method를 호출하지 않습니다.
6. component에 initialize event를 발생시킵니다.
 이 때, component의 모든 children component가 초기되나, component의 size,
 layout이 확정되지는 않습니다. 그러므로 이 event를 이용하여 component가 위치하기
 전의 추가적인 작업을 할 수 있습니다.
7. 상위 컨테이너에 childAdd event가 발생합니다.
8. 상위 컨테이너의 initialize event가 발생합니다.
9. render 이벤트가 발생하는 동안 flex는 다음 동작을 수행합니다.
  9.1 component의 commitProperties method를 호출합니다.
  9.2 component의 measure method를 호출합니다.
  9.3 component의 layoutChrome method를 호출합니다.
  9.4 component의 updateDisplayList method를 호출합니다.
  9.5 component에 updateComplete 이벤트를 발생시킵니다.
10. commitProperties, measure또는 updateDisplayList method가
 invalidateProperties, invalidateSize또는 invalidateDisplayList를 호출하면
 flex는 추가적인 render 이벤트를 발생시킵니다.
11. render 이벤트가 발생된 이후에 flex는 다음 동작을 수행합니다.
  11.1 visible 속성을 true로 설정합니다.
  11.2 creationComplete 이벤트를 발생시킵니다. component의 크기와 layout을
   설정합니다. 이 이벤트는 component가 생성될 때 한 번 호출됩니다.
  11.3 updateComplete 이벤트가 발생합니다.
   flex는 layout, position, size 또는 다른 component의 visual 특성값이 변할
   때마다 추가적으로 updateComplete 이벤트를 발생시키며, compoent의 display가
   갱신됩니다.
12. 다음과 같은 MXML 코드도 동일하게 작동합니다.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">
<mx:Box><mx:Button label="확인"/></mx:Box>
</mx:Application>

Posted by 아주 오래된 미래
04.IT Knowledge/Adobe Flex2007. 6. 29. 12:09
log4j.rootLogger=DEBUG, A2
log4j.appender.A2=org.apache.log4j.FileAppender
log4j.appender.A2.File=fileFullPath
log4j.appender.A2=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A2.DatePattern='.'yyyy-MM-dd
log4j.appender.A2.Append=true
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %x %C.%M(%L) %-5p: %m%n
Posted by 아주 오래된 미래
04.IT Knowledge/단상들2007. 5. 14. 10:39

편하게 쓰겠습니다.

어떻게 하면 인정받는 개발자가 될 수 있는가?
비즈니스와 개발의 경계는 무얼까?

SOA, WEB2.0등등....
이 용어들은 개발자들에게 맞는 용어일까? 비즈니스 전문가에게 맞는 용어일까?

주위의 대다수 사람들이 개발자이다보니 위의 용어들을 이야기하는 사람들이 거의 다 개발자이긴 하지만, 이야기를 나누다 보면 너무 개발자측면으로 이야기하는 것 같아서 조금 씁쓸하다. 물론 본인도 개발자 출신이고, 현재도 마음속으로는 개발자라고 생각하지만, 위의 용어들을 바라보는 시각은 약간은 다른 것 같다.

SOA를 개인적으로 바라보기에는 '날개발'을 예쁘게 치장한 이름 그 이상 이하로도 안 보이며 WEB2.0은 닷컴버블에서 살아나 수익을 올리고 있는 인터넷기반 기업들의 수익모델을 분석해서 그 특징들을 정리해 붙인 용어이지 어떤 특정한 기술요소를 말하는 것은 아니라 생각한다.

그런데, 주위의 개발자들과 이야기해보면, 'WEB2.0은 UCC 등으로 대표되는 양방향성', 'SOA는 웹서비스', 이런 식으로 이야기하곤 한다. 이런 생각은 하루빨리 바꾸고, 고객에게든 같은 개발자그룹내에서든 "WEB2.0은 웹 기반에서 이야기하는 비즈니스 수익 모델을 말하는 것이며, 새로운
기술이 아니라 우리회사와 같이 일하면, 이렇게 이렇게 해서 WEB2.0을 사용해서 소비자에게 더 어필하기 좋게 해드리겠습니다"라거나 "우리회사와 같이 일하시면 이렇게 저렇게 만들어서 (혹은 제공해서) SOA 사상에 걸맞게 사용하실 수 있으며, SOA로 '플젝'을 했기에 소비자에게 '당사는 소비자의 needs를 즉시 반영할 수 있게 됩니다'라고 말할 수 있게 해드리겠습니다"라는 식으로 말하는 사람이 좀 더 많아졌으면 하는 바램이다.

SOA와 WEB2.0이야기는 이쯤하고(다음에 다시하고...), 실제로 쓰고 싶은 이야기를 해보겠다.

개발자라는 직종에서 일하고 있으면, 어떤 강약점을 가지고 있을까? 개발자는 장수하기 위해서 어떻게 해야할까? 혹은 어떻게 성장해야할까?

개인적으로 느낀 점들을 하나씩 풀어보겠다.

1. 개발자는 프로세스에 강하다.

개발이라는 일은 많은 사람들이 말하듯이 '노가다'를 하는 일이 전부가 아니다. 노가다적인 일도 있지만, 개인적으로 생각하는 개발은 그 노가다가 시작되기 전, 즉 설계를 할 때 더 어울리는 말인 것 같다. 그 이후의 노가다는 일이지 개발이 아니다. 하지만, 경험하지 않았다면 노가다는 반드시 겪어야 할 일이라 생각되며 그러면서 게을러짐에 대한 많은 고민을 해야한다. 그런 고민들이 일련의 일들에서 규칙을 찾아내는 힘을 길러주며, 나중에 설계를 하게 될 때 많은 도움을 준다. 그렇게 일련의 과정을 겪은 개발자가 프로세스를 찾아내고, 정규화하고, 정교하게 하는 능력이 약할리 없다고 생각한다. 이런 점은 이 직종에 종사하면서 얻는 아주 좋은 경험이라 생각된다.

2. 개발자는 적어도 하나의 프로그램언어를 다룰 수 있다.

적어도 하나의 언어로 프로젝트에서 주어진 상황을 해결할 수 없다면 단언하건데 당신은 개발자가 아니다. 언젠가 생각해보니, 하나의 언어를 적당한 수준으로 구사하는 것은 그리 큰 일이 아닌 듯 했다. 기본 구문, 파일처리, DB처리, 소켓처리, Thread처리, GUI의 경우 이벤트 처리, WEB의 경우 Cookie/Session처리 정도만 가능하면 프로젝트마다 다르겠지만, 다른 사람의 짐이 되는 것은 어느정도 피할 수 있다. 그리고 이런 처리조차 못한다면, 공부가 부족한 것이다. 불평을 하기전에 공부부터 하시라.

3. 개발자에게 부족한 능력 - 처세(정치력)/마케팅

주위에서 심심치않게 보는 사람들... 10을 일하고, 2정도만 인정받는 사람들...
전에 지인들과의 대화중에 이런 이야기가 있었다.

"XX씨는 10을 일하고 2정도밖에 인정받지 못한다. 그래도 우리처럼 8은 인정받아야지. 만약 15를 인정받는다면 그 사람은 컨설턴트지"라는 이야기에, 씁쓸하게 웃었던 기억이 난다. 이 부분은 포장에 대한 이야기이다.프로젝트 기반으로 살아가는 개발자에게 처세와 포장에 대한 이야기는 꽤나 와닿는 이야기이며, 이 부분에 대해서 마케팅에 관한 책들은 많은 참조거리를 제공해 준다. 마케팅의 컨셉들을 차용해서 프로젝트하는데에 활용한다면 많은 도움이 될것이다. (자세한 이야기는 추후에 하겠다.)

4. 개발자가 관리해야 하는 것 - 경력!!!!

비즈니스 전문가나 컨설턴트들에게도 굉장히 중요한 것이긴 하지만, 개발자에게도 경력관리란 거의 본인의 생명줄이나 다름없다고 생각해야 한다. 우리(개발자)는 발명가가 아니다. 우리가 일하는 이 분야는 이직이 잦으며 연봉은 이직하는 순간에 가장 많이 오른다. 이직할 때 가장 속썩이는 부분이 무엇일까? 영어? 아니다. 바로 경력이다.

가장 쉬운이야기로 어떤 개발자 이모씨가 있다고 했을 때, 그 사람의 이력서를 보면, 언어는 Java와 SQL이지만, Industry가 제조(자동차) + 회계 + 카드 이렇게 구성되어 있다. 다음 이직할 때 일단 은행권 or 보험권 개발자를 구하는 곳에는 들어가기 힘들 뿐 아니라, 들어간다고 해도 원하는 만큼의 연봉상승은 어렵게 된다. 반면, 어떤 개발자 김모씨의 경우 이력서가 줄기차게 유통으로 되어 있다고 하면 김모씨는 유통관련 회사를 계속 다닐생각이 있다면, 적어도 이직에 대한 고민은 거의 없다. 심한 경우 프리랜서도 못할 정도로 꼬셔갈 수도 있다.

중/소기업의 경우 경력관리가 특히나 힘든데, 과감히 이야기하겠다. Industry를 하나 정해서 그것이 흔들리는 회사라면 과감히 다른 회사로 가시라. 사장님께는 죄송하겠지만, 자신을 위해서는 그것이 더 낫다고 생각한다. 차라리 더 좋은데로 빨리 올라가서 그 사장님의 회사와 같이 일을 하시라.

현재 개발과 비즈니스 중간에 걸쳐서 사는 사람이면서 글을 다소 길게 쓴듯 하지만, 올해 초에 JCO 컨퍼런스에 토론 발제했던 것처럼, 개발자라는 직종을 좋아하는 사람 중의 하나로서 사회적으로 인정받는 개발자가 많아졌으면 하는 바람으로 오늘도 고민한다.

감사합니다.

Posted by 아주 오래된 미래
04.IT Knowledge/RDBMS2007. 5. 7. 15:15
 SyBase IQ(이하 IQ)에 대한 짧은 소감.

 IQ는 써본 사람들은 알겠지만, 컬럼 기반의 DB이다.
 IQ는 DB로서 안정성은 다소 떨어지는 것처럼 보이지만, 이 컬럼 기반이라는 것이 어떤
장점을 지니고 있는지 짧게 기술해 보겠다.

 1. Group by 가 살인적으로 빠르다.
  -- 물론 Index가 없으면 빠르지 않겠지만(실제로 상당히 느렸다.), IQ에서 권장하는
    Index를 설정한 경우, Group by 함수(count/sum/min/max 등)의 수행속도는 ....정말
    타DB랑 비교가 안될 정도로 빠르다. ^^/b

 2. Join보다는 update방식의 SQL 수행
  -- 예를 들어 아래와 같은 SQL이 있다고 하자.
      아래의 예는 TABLE2에 있는 고객번호에 해당하는 ROW만 TABLE1에서 COL1기준
    으로 건수를 보는 것이다.
 ********************************  예 1 ******************************************
   SELECT COL2, COUNT(*)
     FROM TABLE1 A
    WHERE EXISTS (SELECT 1
                    FROM TABLE2 B
                   WHERE A.COL1 = B.COL1)
    GROUP BY COL2;
 ******************************************************************************************
      음...위와 같은 SQL을 IQ에서 실행하면, 건수에 따라 다르겠지만 식사를 하고, 차를
     한잔하고 자리에 오면 혹시 수행을 마쳤을 지도 모른다....ㅡ.ㅡ;;;
      위와 같은 SQL을 아래처럼 수행해 보자.
 ********************************  예 2 ********************************************
   SELECT COL1
        , COL2
        , 0    AS FLAG
     INTO #ZZZ
     FROM TABLE1;

   UPDATE #ZZZ   A
      SET A.FLAG = 1
     FROM TABLE2  B
    WHERE A.COL1 = B.COL1;

   SELECT COL2
        , COUNT(*)
     FROM #ZZZ
    WHERE FLAG = 1
    GROUP BY COL2;
 ******************************************************************************************
      위와 같이 수행하면, 예1보다 압도적으로 빠른 실행 시간을 확인할 수 있을 것이다.

 짧은 예시 그리고 간단한 예시이지만, IQ는 컬럼 베이스의 UPDATE방식의 SQL을
작성하므로, 내가 보기에는 초보자에게 적당하며, 구현된 고객사에서의 기능 자체가
DW/DM 쪽이므로 테이블의 구성이 비교적 단순하며, JOIN이 적게 일어나게끔 설계되어있다.
 그러므로, IQ에서 SQL을 구현할 때는
 1. 최종적으로 구할 모수집단을 구하고, 그 모수를 기반으로 컬럼값이 초기화 된 형태의
  TEMP 테이블을 만들고...
 ******************************************************************************************
   SELECT COL1
        , COL2
        , CONVERT(INT,0)              AS COL3
        , CONVERT(NUMERIC(18,0),0)    AS COL4
        , CONVERT(CHAR(400),'')       AS COL5
        , CONVERT(VARCHAR(400),'')    AS COL6
     INTO #ZZZ
     FROM TABLE1;
 ******************************************************************************************
 2. UPDATE에 의한 JOIN을 기반으로 작성해 나가면 된다.

 그럼...
 즐프 하시라~~
Posted by 아주 오래된 미래
04.IT Knowledge/SAS2007. 4. 27. 16:48
상황에 따라 다르겠지만....

/* 실행시간 : 5.12sec */
proc sql;
create table target as
select distinct
       tname
     , cname
     , sum(cnt) as scnt
 from code_freq_master
 group by tname, cname;

create table code_freq_master1 as
select a.yyyymmdd
     , a.tname                                    label="테이블명"
     , a.cname
     , a.vname
     , a.cnt
     , (a.cnt/b.scnt)*100   as cratio format=6.2  label="분포비율"
  from target as b
 inner join code_freq_master a
         on a.tname = b.tname
        and a.cname = b.cname;
quit;
/* 실행시간 : 0.26 + 3.25 + 0.03 + 2.50 = 6.04 */
proc means data=code_freq_master noprint;
       var cnt;
     class tname cname;
    output out=tmp1(where=(_type_=3) ) sum=sum;
run;
proc sort data=code_freq_master ; by tname cname; run;
proc sort data=tmp1 ; by tname cname; run;
data code_freq_master2;
merge code_freq_master(in=in1) tmp1(in=in2 drop=_type_ _freq_);
   by tname cname;
      percent=cnt/sum*100;
   if in1 and in2;
label percent='분포비율'
      sum='합계';
run;


********************************************
*
* Do your best!!
*
* Homepage : http://www.javarang.net
* Javarang Lee
*
********************************************

Posted by 아주 오래된 미래
04.IT Knowledge/SAS2007. 4. 27. 11:40

%macro importData(filename);
data &filename;
%let _EFIERR_ = 0; /* set the ERROR detection macro variable */
infile "c:\SyBase\Code\&filename..txt" delimiter = ',' MISSOVER DSD lrecl=32767 firstobs=1 ;

format yyyymmdd $ 8. ;
format tname $ 24. ;
format cname $ 48. ;
format vname $ 400. ;
format cnt 18. ;

informat yyyymmdd $ 8. ;
informat tname $ 24. ;
informat cname $ 48. ;
informat vname $ 400. ;
informat cnt 18. ;


input
 yyyymmdd $
 tname $
 cname $
 vname $
 cnt
;       
if _ERROR_ then call symput('_EFIERR_',1);  /* set ERROR detection macro variable! */
run;
%mend;

%importData(table1);

********************************************
*
* Do your best!!
*
* Homepage : http://www.javarang.net
* Javarang Lee
*
********************************************

Posted by 아주 오래된 미래