발생일: 2011.05.18

문제:
자연수 m과 n이 있다. 이 두 수의 최대공약수는 어떻게 구할 수 있을까~?

해결책:
유클리드 호제법

int m = 128,
    n = 24,
    k;

do {
    k = m % n;
    m = n;
    n = k;
} while (k != 0);

System.out.print(m);



* 참고: Java의 BigInteger 클래스에 gcd() 메서드가 있기는 하다.
저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2010.02.16

문제:
정확히 어디서부터 이 얘기가 시작되었는 지는 잘 모르겠다.

프렌드 홍과 스트럿츠의 복잡한 요청에 대한 ActionForm 구현에 대해 이야기하다가,
자연스럽게 관계형 DB 에서 지연 로딩 객체 구현에 대한 주제로 넘어가게 됐다.

일반적인 OR Mapping 툴에서 대부분 lazy loading 을 지원한다는데,
(실제 사용해 본 적이 없어 정확히는 모르겠으나, iBatis 의 lazy loading 부분을 책에서 읽어봐 대충 감이 잡혀있긴 하다.)
얘네들은 아무래도 객체형 DB 에 적합할 것 같다는 생각이 들었다.

그럼 객체 자체에 지연 로딩을 적용해 보면 어떨까.

예를 들어, user 객체는 userId 만 가지고 있다가,
userUserName() 과 같은 요청이 들어왔을 때 DB 에 접근해서 사용자 이름을 가져오는 방식으로 말이다.


해결책:
객체 자체에 지연 로딩을 적용해보기 전에 일단 VO 객체가 올바르게 객체 지향으로 재사용되도록 잡아줘야 할 것 같다.

예를 들어, 데이터베이스에 아래와 같은 정보가 있다고 가정해보자.

User (userId, userName, deptId, ... ) // 사용자 정보
Dept (deptId, deptName, ... ) // 부서 정보

각 사용자는 자신의 부서 정보를 포함하고 있다.

몇몇 급조된 프로젝트 - 적어도 홍과 내가 겪었던 - 에서는 사용자 정보와 매핑된 부서 정보를 가져오는 객체를
아래와 같이 한 객체에 정의했다.

class User {
    private String userId;
    private String userName;
    private String deptId; // 사용자 객체에 부서 코드도 포함되어 있다.
    private String deptName; // 부서 이름을 가져오기 위해 DB 에서 부서명도 함께 조회한다.

    // 그 외 getter/setter
}

class Dept { } // 때로 부서 정보만 조회할 때에는 따로 Dept 클래스를 사용하곤 한다.


만약, 게시판 내용을 가져오는 BoardList 라는 VO 객체를 만들었다고 한다면,
위 User 객체를 재사용하지 않고 보통은 아래와 같이 해버리곤 한다. (대부분 '바쁘니까...')

class BoardList { // 게시판 목록 VO 객체
    // 등록자 정보
    private String regUserId;
    private String regUserName;
    private String regUserDeptId;
    private String regUserDeptName;
    // 최근 수정자 정보
    private String updateUserId;
    private String updateUserName;
    private String updateUserDeptId;
    private String updateUserDeptName;

    // 그 외 getter/setter
}


가끔은 deptId 부분이 쓰이지 않을 것 같으면 그냥 deptId 에 deptName 을 넣기도 한다.


이 User 객체를 아래와 같이 좀 더 객체 지향으로 리팩토링 할 수 있다.

class User {
    private String userId;
    private String userName;
    private Dept dept; // 부서 정보는 부서 객체를 사용한다.

    // getter / setter
}

class Dept {
    private String deptId;
    private String deptName;

    // getter / setter
}

BoardList 에서도 User 객체를 활용한다.

class BoardList {
    private User regUser;
    private User updateUser;
}



이제 어느 정도 객체 지향적인 모습을 띄었다.
이제 이 객체에 지연 로딩(lazy loading) 을 적용해 보려고 한다.

기본적으로 primary key 가 되는 값만 전달해주고, 추가 요청이 생길 경우 상세 내용을 DB에서 가져오는 방식이다.

class User {   
    String userId;
    String userName;
    Dept dept;
   
    public User(String userId) {
        this.userId = userId;
    }
   
    public void set() {
        // DB 에서 user 정보를 가져오고, 같은 row 내 deptId 로 dept 객체를 생성해둔다.
        // set 하는 부분은 구현하기 나름이겠다.
        Map result = dao.getUserMap(userId);
        userName = (String) result.get("userName");
        dept = new Dept((String) result.get("deptId"));
    }
   
    public String getUserId() {
        return userId;
    }
   
    public Strin getUserName() {
        if (userName == null) set(); // userName 등 상세정보가 없을 경우 set() 한다
        return userName;
    }
   
    public Dept getDept() {
        return dept;
    }
}

class Dept() {   
    String deptId;
    String deptName;
   
    public Dept(String deptId) {
        this.deptId = deptId;
    }
   
    void set() {
        // 디비에서 deptId에 해당하는 부서 정보를 가져온다.
        dao.getDept(deptId);
    }
   
    public String deptName() {
        if (deptName == null) set(); // 역시 lazy loading
        return deptName;
    }
}


이렇게 할 경우, userId 만 있으면 필요한 시점에 상세 정보를 DB 에서 가져올 수 있다.
코드가 간략해지고 짧아짐은 물론이다.

만약, 전체 목록을 가져오는 등의 상황을 고려한다면 퍼포먼스 측면에서 그리 추천할 만한 방법은 아닐 것 같다.
(홍은 목록이 10~20 여개 정도라면 크게 문제되지 않을 것 같다고 한다)

아직 실제로 구현해보지는 않았으나, 이런 방식으로 빈을 만든다면 상세 정보 호출에 대한 수고가 크게 줄어들 게 된다.

예를 들어, 게시물에 대한 Board 라는 VO 를 생각해보자.

class Board {
    private String title;
    private String content;
    private User author;

    public void set() {
        // Board 객체도 set() 메서드가 있다고 가정하고,
        // DB 에서 author 에 대한 userId 값을 가지고 user 객체를 생성해뒀다고 치자.
        ... (설정 중략) ...
        ahthor = new User((String) dao.getBoardDetail("author_id")); // author_id 가 작성자 id라고 가정
    }
    // getter / setter
}

board 객체만 가져오면 그 이후부터는 필요할 때마다 객체에서 직접 상세 내용을 가져오도록 할 수 있다.

board.getAuthor().getUserName()
board.getAuthor().getDept().getDeptName()

과 같이 상세 내용을 호출하면 필요할 때 그 내용을 직접 가져오게 된다.

코드도 굉장히 짧아지고, 각자 자기 역할을 충실히 해 낸다.

공통되는 set() 부분이나 null check 부분을 인터페이스로 뽑아내도 좋을 것 같고, (LazyBean 같은 이름으로)
아니면 dao 를 가지고 있는 부모 클래스를 두고 확장하도록 해도 괜찮을 것 같다.

iBatis 에서는 result-map 을 이용해 서브 쿼리를 필요할 때 실행해서 가져오도록 하던데,
이 방법도 적합하게 사용된다면 아주 유용할 것이라 생각한다.





저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.12.30

문제:
이번 프로젝트에서는 S모 사에서 수집해준 데이터를 받아온다.
교육 과정에서 들은 이야기인데,
이 업체에서 만든 수집 엔진(웹 크롤러)는
문서의 수집 주기를 (인공지능이라고까지 하기는 뭐하고) 동적으로 설정한다고 한다.

어떤 방법일까?

해결책:
일단 최초 수집 시에는 기본 설정 단위 기간 (대략 5분 정도) 으로 같은 페이지에 접근해 수집한다.
(IP 차단 등 블러킹에 대한 예외는 없다고 가정한다)

이후, 일정 시도만큼의 수집이 종료된 후에,
추가 수집된 데이터의 양을 고려해 최적화된 수집 주기를 설정하게 된다.

예를 들어, A 사이트에서 최근 5분 이내에 수집된 평균 데이터가 많을 경우 그에 따라 수집 주기를 단축하고,
수집된 평균 데이터가 수 건 정도라면 수집 주기를 늘리는 식이다.

주기적으로 계속 수집 주기를 변경하면서 최적화된 수집 주기를 찾아가는 거다.

잠깐 생각해봤을 때,...
최근 평균 수집 데이터 건수 / 평균 수집 건수 정의 / 수집 주기 / 수집 건수 기준 / 단위 기간

등을 고려해 봐야할 것 같다.


쉽게 이해할 수 있는 개념이지만, 아이디어가 좋아 메모해둔다.

이런 최적화 로직은 여러 모로 유용할 것 같단 생각이 든다.



#그 외 참고.

    자바 웹크롤러(Java Web Crawler) 구현시 고려사항 들..

개인이 간단히 크롤러를 구현해보고 느낀 고려 사항들을 정리해둔 포스트이다.
직접 구현해보지 않은 사람들이 읽기에도 공감할 수 있도록 고려할 점들을 쉽게 설명해뒀다.

본문 내에 있는 스레드풀 구현 예제에 대한 링크가 좋다. 함께 참고해보자.



제목처럼 대용량 검색 엔진을 위한 병렬 웹 크롤러 구현에 대한 논문이다.
여러 대의 머신을 이용하여 대량의 웹 페이지를 빠르게 수집하기 위한 아키텍처와 모델에 대해 설명되어 있다.
링크에 대한 중요도 설정과 중복 제거에 대한 알고리즘 등도 있는데 사실 잘 이해가 되진 않는다.^^;

* DBPIA 라는 학술 논문 사이트인 것 같은데, 회사 IP라 기관 회원이라 해당 파일에 대한 원문 조회가 되는 모양이다.





저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.12.30

문제:
대형 쇼핑몰을 보면 메인 화면부터 물품 정보로 가득 차 있다.

메인 페이지의 경우 특히나 트래픽이 많을 것 같은데,
매번 물품 정보에 대한 내용을 DB 에서 가져오면 꽤 부담스러울 것 같다.
인기 모델이나 메인에 들어갈 모델을 따로 테이블로 뽑아 놓는다 하더라도,
DB 커넥션에만 드는 비용을 무시할 수 없을 것 같다.

헌데 각 쇼핑몰에 접속해보면, 그닥 느리지 않다.
플래시나 html 을 그리는 데 시간이 걸리는 게 있어 좀 버벅거린다 싶을 뿐이지,
데이터를 로딩하는 데에는 문제가 없는 것 같다.

어떤 식으로 처리하는 걸까?


해결책:
얼마 전 프렌드 홍이 들었던 어떤 수업의 강사 분이 11번가 프로젝트에 참여했었다고 한다.
그 아저씨가 얘기해주시기를,
쇼핑몰 같이 트래픽이 큰 사이트들은 메인 페이지를 주기적으로 정적인 html 로 구워놓는다고 한다.
(일종의 프록시 패턴이라고 할 수도 있을 것 같다.)

11번가에 접속해 확인해보니, 메인 페이지 뿐만 아니라 각 카테고리의 메인 페이지도 html 로 구현되어 있었다.

11번가 메이 페이지 URL 주소



메인 페이지 좌측 상단의 '베스트플러스' 메뉴를 클릭해보니, 이 페이지도 html 형태이다.

11번가 베스트플러스 페이지 URL 주소



물론, 요청에 대한 url mapping suffix 가 html 수도 있으나,
폴더명 등을 유추해봤을 때 (WAS 에서 뿌려주든 IIS 에서 보여주든 여튼,) 구워진 html 이라고 생각하면 될 것 같다.

그 외에 카테고리 메인 등에도 html 형태로 표시하긴 하나, parameter 를 받는 걸 보면 꼭 정적인 페이지는 아닌가보다.

11번가 특정 카테고리 메인 URL 주소




상세보기나 다른 페이지들을 보면 tmall 등 suffix 가 있어 이 때는 동적으로 가져와 보여주는 것 같다.

11번가 상세보기 페이지 URL 주소




자세한 구현 방식 등은 URL 만 보고 판단할 건 아니지만,
대충 이런 방법으로 하면 효율적이고 좋겠구나. 라고 생각하고 상황에 맞게 잘 활용하면 되겠다.

트래픽이 많은 사이트에 대한 노하우나 튜닝 등에 대한 서적이나 문서도 많을 것 같은데,
한 번 찾아봐야겠다.

(혹시 알고 계시는 분이 있으면 알려주세요~)


저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.12.09

문제:
친구 홍네 파트 연구회에서는 스윙으로 릴리즈 프로그램을 만들고 있다고 한다.
헌데, 아무래도 UI 가 문제인 모양이다. 다들 웹만 하다보니 스윙에는 그닥 익숙치 않아서인 듯 하다.

나도 스윙은 많이 해보지 못했지만 스윙의 UI 는 좀 답답하다.
게다가 간단한 프로그램만 만들려고 해도 영~ 촌스러운 게 모양이 잘 안나온다.ㅎㅎ

이클립스 플러그인으로 구현하면 좋을 듯 싶으나, 잘 모르겠다. -_-a

음... 그렇다면,
로컬 환경에서 브라우저와 자바 파일을 이용해 개발할 수 있는 방법이 있을까...?

생각해보자.


해결책:
로컬에서만 돌아갈 프로그램이라면 이런 방법도 괜찮겠다.

브라우저에서 UI를 구현하고, 브라우저에서 자바 파일을 실행(배치파일을 실행) 하게 하는 식으로 개발하는 거다.

전체적인 프로세는 이렇다.

        브라우저 (UI 담당)     ----------- (실행) ---------->    자바 파일
                   |                                                                       |
                   |                                                                       |
          진행 상태 확인        <----- (AJAX로 확인) ------->    로그 파일



[실행]
다행히 브라우저에서 exe 파일을 실행할 수 있기는 한가보다.
object 태그를 쓰는 방식으로 말이다. (웹페이지(HTML)에서 직접 실행파일(exe) 실행시키기 참고)

아직 안해봤지만, java 실행 구문을 배치파일(.bat) 로 만들어서 돌리면 어떨까 하는데,
이것도 object 태그에서 불러질 지는 의문이다.

정 안된다면, 실행파일을 exe 로 만드는 꼼수를 사용해야 할 듯 하다.

+ 추가 :
    a 태그의 href 로 .bat 파일의 상대경로를 넣는 방식으로 추가할 수 있다.
    단, IE 에서만 지원하며 -_-... bat 파일 실행 시 보안 경고가 뜬다.


[진행 상태 확인]
실행이 가능하다면, 잘 실행되었는지, 상태는 어떤지 확인해야 한다.

일단 실행 후, 실행에 따라 자바 파일에서 파일로 로그를 작성한다.
브라우저에서는 AJAX로 이 파일의 내용을 읽어와 진행 상태를 확인하자는 아이디어다.

로그 파일을 작성할 때 몇 가지 고려해야 될 점이 있다.

  - 실행 아이디
     브라우저에서는 실시간으로 로그 파일에 접근해 내용을 가져와 보여주므로,
     어떤 실행에 대한 로그인 지 알아야 한다.
     브라우저에서 java 파일을 호출할 때, 실행 아이디를 생성해 넘겨주고,
     파일에서는 로그 파일을 작성할 때 어떤 실행에 대한 상태 로그인지 작성해줘야겠다.

  - 파일 확장자 (xml)
     지금 생각으로는 로그 파일이 xml 형태라면 브라우저에서 파싱하고 보여주기에 적합할 것 같다.



음... 가능할까?

시간날 때 한 번 구현해봐야겠다.
    
저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.12.03

문제:
담당하고 있는 시스템의 분석 엔진은 문장 분석 기능을 가지고 있다.

'나는 아이스크림이 좋아요.' 라는 문장을 가지고,
[나 - 아이스크림 - 좋다] 라는 (긍정의) 의미를 뽑아낼 수 있는 거다.

일전에 검색 세미나(STS 2009)에 다녀왔을 때,
시맨틱 웹과 온톨로지라는 개념에 대해 설명을 들었었는데...
아마, 우리 분석 엔진에서 사용한 게 바로 온톨로지라는 개념이 아닐까 싶다.

컴퓨터가 문장을 이해할 수 있도록 해준 게 아마 분석의 기반이 되는 '언어 사전'일 테고,
큰 맥락에서 이 사전이 온톨로지일 것이란 생각도 든다.
사전이 곧 정보의 개념과 관계에 대한 구체적인 설명을 해주니까...

시맨틱 웹에서는 태그 등을 통해 그 의미를 분석할 테고 말이다.

아... 그래도 이해하기 어렵다...

온톨로지가 정확히 뭐냐.


해결책:
아직도 아리까리 하지만,...
일단 몇 가지 이해하는 데 도움이 될 만한 링크이다.



저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.11.20

문제:
프렌드 홍이 Google Wave 에 대한 내용에 들어있는 포스트 링크를 줬다.

(동영상도 재밌고 유익하다. 시간을 내서라도 쭉 보도록 하자.)

얘네들을 보면, 변경 사항이 각 페이지를 보고 있는 사용자에게 실시간으로 보여진다.
Google Talk 이나 Google Doc 에도 이미 있는 기능이긴 하던데,..
아마 서버 푸시 방식으로 요청을 처리하고 있는 것 같다. (옵저버 패턴처럼 말이다...)

이건 어떻게 구현하는 걸까?

해결책:
홍이 Resin 이라고, 이런 방식을 제공하는 서버가 있다며, 잘 정리된 포스트가 있다고 알려준다.
더불어, 이런 Server Push 방식을 Comet 이라고 한다고 알려줬다.

Comet 이란 웹 클라이언트(보통 웹 브라우저)의 명시적인 요청이 없어도
서버에서 클라이언트로 데이타를 밀어넣는(Push) 방식으로 동작하는 웹 프로그래밍 모델을 일컫는 말이라 한다.

자세한 내용은 아래 포스트를 참고하자.


저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.10.29

문제:
후배 P에게 아직 비밀번호 변경하기 기능이 구현이 되지 않은 시스템에 기능을 추가해보라고 했다.
그리고는 같이 네이버나 다음, 구글의 경우 어떤 식으로 로직을 처리하는지 한 번씩 찾아봤다.


해결책:
네이버는 다른 백업 메일을 가지고 있지 않아 다음과 구글만 확인해보기로 했다.

내부적으로 두 사이트 모두 전체적인 로직은 다음과 같다. (여기서는 메일을 이용해 찾는 기능만 고려했다)
   비밀번호 찾기 ---> 백업 메일로 임시비밀번호 또는 비밀번호 찾기 링크 전송
   ---> 전송받은 메일 페이지에서 비밀번호 변경 페이지로 이동
   ---> 임시비밀번호를 통해(또는 링크로 전달된 값으로 자동 설정) 비밀번호 변경


다음과 구글의 차이가 있다면, 다음과 같다.

[다음]
다음의 경우, 비밀번호 변경 요청을 하면 아래와 같이 임시비밀번호가 포함된 메일을 발송한다.

다음의 비밀번호 변경


'비밀번호 바로 변경하기' 버튼의 링크를 누르면 아래와 같이 비밀번호 변경 페이지로 이동한다.

다음의 비밀번호 변경 페이지

위 링크는 https://user.daum.net/daumuser/tempPWMail.user 형태의 주소로 언제나 접근이 가능하다.


[구글]
구글의 경우 아래와 같이 비밀번호 변경 페이지로 이동할 수 있는 링크를 준다.
이 링크에는 암호화된 코드가 포함되어 있다.

구글의 비밀번호 변경 메일

해당 링크를 통해 비밀번호 변경 페이지로 이동하면, 아래와 같은 페이지가 나온다.


GET 요청의 패러미터로 전달된 값을 통해 어떤 유저인지 파악이 가능하여,
아이디나 임시비밀번호를 넣을 필요없이 바로 비밀번호를 변경할 수 있다.
물론 잘못된 키를 입력하여 임의로 변경 페이지에 접근하려고 했을 떄에는 접근이 불가능하다.


두 방법의 로직이 거의 흡사하기 때문에 어느 쪽으로 구현하든 크게 상관은 없을 것 같다.
하지만, 개인적으로는 구글의 방법이 좋다. 아무래도 사용자 입장에서 작성할 내용이 몇 개 없으니까^^

하지만, 역시 친숙하기는 다음의 것이 훨씬 낫다.
구글 메일에서도 적어도 해당 URL에 링크를 걸어줬으면 더 좋지 않았을까 하는 생각이 든다.


* 기타 주의점
- 최초 구글 메일 변경을 시도했을 때, 내가 예전에 사용하던 메일로 임시변경 메일이 전송됐다.
  그 메일은 지금 사용할 수가 없기 때문에 "비밀번호가 잠겨버렸을까... X 됐다" 라고 생각하고 있었다. -_-;
  (구글의 경우, 메일 찾기 기능을 다시 사용하려면 1회 요청 후 24시간 이후에 할 수 있다.)
  헌데 다행히 예전 비밀번호로 접속이 가능하다.
  비밀번호 변경을 시도하기 전까지는 예전 비밀번호를 그대로 유지하는 거다...

- 중요한 것은, '임시비밀번호'가 실제 '비밀번호'는 아니라는 거다. (다음의 '임시비밀번호' 든, 구글의 '링크 키값'이든)
  임시비밀번호는 단지, 비밀번호를 변경하기 위한 통로를 제공해주는 것 뿐이다.
  혹시나 실제 비밀번호를 임시로 바꿔 그 값을 전송해주는 일이 절대로 없도록 하자.
  비밀번호는 사용자가 변경하는 거다.


저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.06.30

문제:
구글 코드잼 문제를 풀다보니, 중국인의 나머지 정리(Chinese remainder theorem)가 적용되어야 했다.
중국인의 나머지 정리라... 당췌 이게 뭔지 모르겠다.... -_-a.

해결책:
중국인의 나머지 정리에 대해 쉽게 정리해 둔 블로그가 있다.
어느 정도 감이 잡히기는 하는데,...
아직 잘 모르겠다. @_@

10 이하의 소수 중 하나(2 또는 3, 5, 7)로 나눠지는 수 x 가 있다.
근데 이 x의 수가 꽤 크다면, 아래와 같이 계산한 x' 도 10 이하의 소수 중 하나로 나눠진다고 한다.

x' = x MOD (2 * 3 * 5 * 7)

왜 그런 걸까...... -_-a
알려주세요....


* 팁: 수학사랑 사이트에서 주요 수학 정리에 대해 잘 설명해두었다.

저작자 표시 비영리 변경 금지
Posted by ohgyun
발생일: 2009.05.29

문제:
인기도를 파악하여 현재 가장 인기있는 게시물을 보여주고자 한다.

단순히 조회수 순으로 보여주자니 한때 조회수가 많았던 데이터가 너무 오랫동안 탑을 차지한다.
뭔가 다른 효과적인 방법이 없을까?

해결책:
세계적인 사진 공유 사이트인 flickr에서는 사진의 인기 정도를 Interestingness 라고 정의했다.
Interestingness. 즉 그 시점에서 얼마나 인기있는가? 재미있는가? 를 묻는 것이다.

그럼 어떻게 interestingness를 측정해야 할까...?

인기도를 적용하려는 사이트의 특성마다 다르겠지만,
interestingness의 측정에 대해 토의한 포럼을 보니 좋은 아이디어가 많다.


생각을 보태서 정리해보면...

Interestingness에 영향을 주는 요소는 대략 아래와 같겠다.
  • 상세보기 조회수
  • 그림 로드 수
  • 즐겨찾기에 추가된 수
  • 댓글 수
  • 오래된 정도(cliche 정도 생각하면 되겠다) : (현재 시간 - 등록된 시간) / 단위
  • (인기 태그 사용 수 : 추후 생각)
각 요소에 포인트를 부여해 그 합계를 interestingness 로 측정하면
현재 시점에서 해당 그림의 인기를 어느 정도 파악할 수 있지 않을까....

좀더 나은 방법에 대해서도 생각이 필요하다.



저작자 표시 비영리 변경 금지
Posted by ohgyun