Whiteship's Note

'모하니?'에 해당되는 글 934건

  1. 2009.09.24 비행기 갈아타야 할 때는... 시간을 좀 넉넉하게 (10)
  2. 2009.09.23 역시 개발자는 모니터가 빵빵한듯... (14)
  3. 2009.09.23 역시 개발자들은 파이어폭스인가.. (12)
  4. 2009.09.23 [NotificationService] NotificationService 인터페이스 기반 프로그래밍 (2)
  5. 2009.09.23 테스트 환경와 운영 환경용 설정 분리/구분하기 (4)
  6. 2009.09.21 [봄싹] 매주 토요일 (12)
  7. 2009.09.18 [봄싹] 스프링 레퍼런스 3.0 번역 시작 (4)
  8. 2009.09.15 초고속 로보트 손
  9. 2009.09.15 봄싹 9월 특강 Completed!! 후기랄까나... (8)
  10. 2009.09.14 스프링 이메일 확장하기 3
  11. 2009.09.12 스프링 이메일 확장하기 2
  12. 2009.09.10 [하이버네이트] 쿼리를 수정할 것이냐 모델을 수정할 것이냐...
  13. 2009.09.09 완전 부럽다... (22)
  14. 2009.09.08 [하이버네이트] 1 + 2N select 문제 해결하기 (4)
  15. 2009.09.07 [hamcrest] Matcher 만들기
  16. 2009.09.04 [GenericDao] 하이버네이트 GenericDao (6)
  17. 2009.09.04 [Generic] 자바 Generic 타입 알아내기
  18. 2009.09.02 [EGIU] Unit 19, 20정리
  19. 2009.08.31 쓰리좝 시작인가... (6)
  20. 2009.08.31 9월에 할 일 정리 (10)
  21. 2009.08.27 [봄싹 오픈] springsprout.org (20)
  22. 2009.08.27 [봄싹] D-day 오후 10시에 오픈하겠습니다. (4)
  23. 2009.08.26 [봄싹] 시즌 2 오픈 D-1 (2)
  24. 2009.08.17 [봄싹] 시즌2 다음 주 오픈 예정 (2)
  25. 2009.08.17 [잡담] 예비군 4년차 훈련 시간 (10)
  26. 2009.08.14 [테스트] 커스텀 MimeMessageHelper 테스트하기
  27. 2009.08.14 [스프링 이메일] MimeMessageHelper 초간단히 사용하기
  28. 2009.08.13 허경영의 콜미
  29. 2009.08.11 제주도 또 가겠구나~ (10)
  30. 2009.08.11 [EGIU] Unit 13, 14 정리

비행기 갈아타야 할 때는... 시간을 좀 넉넉하게

모하니?/Thinking : 2009. 9. 24. 23:44


잡았어야 하는데... 큰일이로군요.

11시 25분에 떨어지는데 1시 뱅기로 갈아타야 합니다.

어떻게 보면 가능할 것 같기도 하지만.. 사실 굉장히 힘든 시간입니다.

원래는 1시반으로 예약을 해뒀었는데. 시간이 계속 바뀌더니 현재는 1시로 바뀌었습니다.

헐... -_-;; 부랴부랴 연락을 해뒀지만 부정적입니다. 아무런 대처도 안해줍니다.

프로모션 티켓이라 변경도 안되고 그냥 버리고 새로 사라는데 어이가 없더군요.

그럼 빨리 갈아탈 수 있게 가이드라도 해달라고 했는데 그것도 안 된답니다.

씨에어 이 개떡같은 것들아 니네꺼 다시는 안 탈꺼야!!!

이건 뭐 가기도 전에 스트레스 받아서 쓰러질 것 같아요.

흑흑흑...

최악의 경우 뱅기를 놓치고 당일 오후 늦은 뱅기표를 사서 아주 개고생을 하게 생겼네요.

에휴.. 이게다..  변수를 생각지 못하고 예약을 해버린 제 불찰입니다.

일정이 변경될 여지를 생각해서 최소한 3시간 텀은 두는게 안전할 것 같습니다.

아니면 아예 하루 자고 나서 갈아타던지 말이죠.

암튼.. 코딩도 못하고 공부도 못해서 재미도 없고 피곤하고 짜증나는 하루였네요.

뭐.. 이런 날도 있는거겠죠.
top

  1. Favicon of http://toby.epril.com BlogIcon 토비 2009.09.25 05:19 PERM. MOD/DEL REPLY

    갈아타는 시간이 한시간 반이면 넉넉하구만.
    나는 40분 안에 갈아타는 것도 해봤는데.
    미리 공항지도랑 정보를 찾아서 공부해두셈.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.25 08:56 PERM MOD/DEL

    국내선이 좀 떨어져있더라구요. ㅠ.ㅠ
    오늘은 공항지도를 프리즌 프레이크처럼 새겨두려구요.

  2. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.25 12:11 PERM. MOD/DEL REPLY

    순리대로 하면 편하다니깐욤
    쓸데없는걸로 스트렛 받지 말자규~

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.25 12:29 PERM MOD/DEL

    순리대로, 지들이 일정을 바꿔서 손님한테 피해가왔으면 적당히 배려를 해줘야지...

    맘에 안들어.. 씨에어!! 잊지 않겠다!

  3. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.26 05:58 PERM. MOD/DEL REPLY

    어디 가시나 봐요? :)

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.26 08:00 PERM MOD/DEL

    넹 보라카이요.

  4. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.27 14:11 PERM. MOD/DEL REPLY

    와~! 여행가시나 봐요?
    재밌게 즐기다 오세요. :)

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.27 22:34 PERM MOD/DEL

    네. 효도관광 삼아 다녀오려구요. ^^;
    무사히 다녀와야죠~

  5. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.28 14:35 PERM. MOD/DEL REPLY

    아... 효도관광이었군요. 좋은일 하시네요. :)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.28 18:20 신고 PERM MOD/DEL

    네... 내일 모래인데;; 아직 준비가 좀...
    헉;; 어서 집에가야지 ㅠ.ㅠ

Write a comment.


역시 개발자는 모니터가 빵빵한듯...

모하니?/그냥 놀아 : 2009. 9. 23. 20:40


진짜 집에 가려고 했는데;; 아주 특이한 분석자료가 있어서요..ㅋㅋ


1위인 1280이 요즘은 대세가 되서 그런걸지도 모르겠지만,
2위인 1680*1050 해상도로 거의 절반 가까이가 접속하셨네요..
세상에...

다들.. 그정도는 쓰시는군요. ^^
1680*1050 안쓰시는 분들만 조금 답답한 거죠 뭐.ㅋㅋㅋ


top

  1. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.23 21:03 PERM. MOD/DEL REPLY

    http://codemonkeyism.com/7-signs-work-software-company/
    :)
    저도 더 좋은 컴에 듀얼 모니터 써야 하는데... ㅠ_ㅠ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.23 22:45 신고 PERM MOD/DEL

    A company should respect their developers. As with good tools, decent hardware helps developers to turn more requirements into working code.

    이거로군요.ㅋㅋㅋ

  2. Favicon of http://toby.epril.com BlogIcon 토비 2009.09.23 23:04 PERM. MOD/DEL REPLY

    모니터가 커질 수록 본 업무 외에 딴 짓을 많이한다는 연구결과도 있어

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.23 23:21 신고 PERM MOD/DEL

    네. 들어본 것 같아요.

    근데 듀얼은 정말 필요한 듯.. 한쪽에는 이클립스 띄우고 한 쪽에는 브라우저 띄우고ㅋ

  3. Favicon of http://parksk.tistory.com BlogIcon 박상근 2009.09.24 02:41 PERM. MOD/DEL REPLY

    이전에 스던 15.4 인치 노트북 해상도가 1680*1050 이었습니다. ㅎㅎㅎ
    여기에 20.1 인치 와이드 모니터를 듀얼로 썼었는데,
    노트북이 너무 무거워서 12.1인치로 바꾸고서, 이것과 20.1 와이드 모니터로 듀얼 구성중입니다.

    아무래도 개발 하려면 듀얼 모니터가 필수겠죠.
    개발툴 외에 메신저, 뮤직플레이어 등을 따로 둘 모니터가... :D

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.24 09:25 PERM MOD/DEL

    네;; 맞아요. 기타.. MySQL 어드민을 띄우든, PgAdmin을 띄우든. 조그만 창으로 뜨는 것들을 모아둘 모니터도 하나 필요한 듯..

    결국은.. 모니터가 세 개정도는 있어야...ㅋㅋ

  4. Favicon of http://www.value25.com/ BlogIcon 쌈바스 2009.09.24 20:30 PERM. MOD/DEL REPLY

    전 본체는 아주 저렴한걸로 하는 대신 모니터는 17인치 CRT에서 26인치(1920*1200) 바꾸니

    너무 좋더라구요~ 꼭 전세에서 내 집 생긴 기분이랄까요~허허 (조금 자랑했습니다.^^:;)

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.24 23:33 PERM MOD/DEL

    헉... 26인치.. 듀얼 모니터 필요 없겠네요!!

  5. Favicon of http://deuxksy.tistory.com BlogIcon 김석영 2009.09.24 20:45 PERM. MOD/DEL REPLY

    전 71명중에 1명 이랍니다!~ 훗 나의 눈은 소중 하니깐!~

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.24 23:34 PERM MOD/DEL

    캬.. 가장 높은 해상도로군요. 축!!

  6. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.24 23:02 PERM. MOD/DEL REPLY

    후루꾸꾸루후으으후루꾸꾸루후으으후루꾸꾸루후으으후루꾸꾸루후으으후루꾸꾸루후으으후루꾸꾸루후으으후루꾸꾸루후으

    해상도가 좋은 모니터도 이 글씨는 춤춰 보이겠지?
    마구 춤추는거 같어.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.24 23:34 PERM MOD/DEL

    오징어 그만 다듬고 어여 자..

  7. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.25 12:10 PERM. MOD/DEL REPLY

    아침에 맛나게 먹어줬으니 괜찮어.

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.25 12:28 PERM MOD/DEL

    ㅇㅇ맛있었어. 귿!!

Write a comment.


역시 개발자들은 파이어폭스인가..

모하니?/그냥 놀아 : 2009. 9. 23. 20:33



봄싹 사이트에 접속한 사용자들(대부분이 개발자시겠죠?)이 사용하는 브라우저 분석을 봤더니 IE 보다 파이어폭스 유저가 더 많네요.

참고로 봄싹사이트에 IE6로 접근하시면 재미난 걸 보실 수 있습니다. ㅋㅋ

ps: 이젠 진짜 집에가야지;

top

  1. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.23 20:55 PERM. MOD/DEL REPLY

    IE는 만든 어플이 잘 돌아가는지 확인 할때만 쓰고
    대부분 FireFox, Opera, Google Chrome 을 사용합니다.
    Linux라 Safari는 사용할수가 없어 아쉽네요.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.23 22:34 신고 PERM MOD/DEL

    넹 전 인터넷 쇼핑 할때만 써요.ㅋㅋ
    아.. 회사일 할때도 쓰는군요. 회사에서 만드는 시스템 사용자는 대부분 IE를 사용하시는 지라...

  2. Favicon of http://deuxksy.tistory.com BlogIcon 김석영 2009.09.24 20:46 PERM. MOD/DEL REPLY

    당최 블랙베리는 누굴까요?

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.24 23:37 PERM MOD/DEL

    글쎄요; 전 그게 뭔지도 몰겠네요.

  3. Favicon of http://deuxksy.tistory.com BlogIcon 김석영 2009.09.25 00:18 PERM. MOD/DEL REPLY

    블랙베리 PDA 폰입니다.
    오바마 횽아가 쓰는 폰이라조...
    설마 오바마 횽아가 오셨을리는 없고 누굴지 궁금합니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.25 00:24 신고 PERM MOD/DEL

    아항; 글쿤요.
    아이폰 떡밥이 계속 나오던데.. 이젠 나오던 말던 너무 지쳐서 별로 사고 싶지도 않네요.

  4. 쿠크다스 2009.09.26 15:01 PERM. MOD/DEL REPLY

    웹개발자의 벗 - 파폭과 그 애드온들

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.26 15:07 PERM MOD/DEL

    네! 파이어버그 짱이죠~

  5. Favicon of http://deuxksy.tistory.com BlogIcon 김석영 2009.09.28 03:10 PERM. MOD/DEL REPLY

    아이폰 나오는거는 거의 기정사실이 아닌가 합니다
    용자께서 전파연구소를 통해서 KT 가 아닌 SKT 신청해놓은걸로 압니다.
    아이폰이 올해 나올지 상상도 못해서 저는 최근에 Xperia-X1을 저번주에 지른게 약간
    후회가 되지만 뭐 그래도 지금 휴대폰에 만족합니다.

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.28 09:28 PERM MOD/DEL

    넹. 전 아이팟터치랑 핸드폰 따로 들고 다니기가 귀찮아서 나오면 사려고 했는데.. 약정이나 기계요금을 비싸게 받으면 안 사려구요.

  6. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.28 14:40 PERM. MOD/DEL REPLY

    제 친구가 아이폰 쓰는데, 진짜 좋아 보이긴 하더군요...
    깔끔하고 이쁘고...
    근데 저는 안드로이드 깔린 폰이 더 끌리네요. :)
    HTC Dream처럼 키보드 따로 달리고
    모양은 그거보다 좀 이쁘고
    스펙도 좀더 괜찮은거 나오길 바라고 있습니다.
    근데 당장 이게 필요한게 아니라서... 나와도 안 살것 같습니다...@_@;

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.28 18:22 신고 PERM MOD/DEL

    네ㅎㅎ안드로이드에 키보드.. 캬..
    미니 컴터로군요.

Write a comment.


[NotificationService] NotificationService 인터페이스 기반 프로그래밍

모하니?/Coding : 2009. 9. 23. 20:08


봄싹 사이트에서는 여러 종류(이메일, 구글토크, 트위터, 미투데이 등등)의 알림 서비스를 제공할 계획입니다. 현재는 이 중에서 미투데이를 뺀 나머지 세 개의 서비스가 구현되어 있습니다.

이메일은 스프링의 JavaMailSender를 이용했고, 구글 토크는 Smack 라이브러를 이용했고 트위터는 twiiter4j 라이브러를 이용했습니다.

메일 기능을 만들 때는 인터페이스를 고려하지 않았었는데, 구글 토크 서비스를 만들 때는 인터페이스를 생가해서 미리 MessangerService라는 걸 만들었었습니다.

public interface MessagangerService {
   
    void sendMessage(SpringSproutMessage ssm);

}

SpringSproutMesage 타입의 객체를 받아서 어떤 메시지를 전송하는 인터페이스를 만들고, 그것을 구현한 JabberMessagangerService를 만들었습니다.

public class JabberMessangerService implements NotificationService {
   
...
   
    public void sendMessage(SpringSproutMessage ssm) {
      ...
    }

}


그런다음 메시지들을 몇 개 만들었습니다.

public abstract class SpringSproutMessage {
   
    protected StringBuilder msg;
    protected Collection<String> tos;
   
    public SpringSproutMessage() {
        msg = new StringBuilder();
    }
   
    public String getMessage() {
        return msg.toString();
    }

    public Collection<String> getTos() {
        return tos;
    }
   
}

메시지에서 기본으로 필요한 속성들을 가지고 있는 상위 클래스를 제공하기로 했습니다.

public class MeetingMessage extends SpringSproutMessage{

    public MeetingMessage(Study study, Meeting meeting, MeetingStatus status) {
      ...
    }

    public MeetingMessage(Meeting meeting, MeetingStatus status) {
        this(meeting.getStudy(), meeting, status);
    }

}


이런식으로 상속 받아서 필요한 메시지는 주로 생성자에서 만들어 채웁니다.

    @AfterReturning(pointcut = "addStudyPointcut() && args(study)", argNames="study")
    public void sendMailAfterAddStudy(Study study){
        sendMailService.sendMail(new StudyMail(study, StudyStatus.OPEN));
        messangerService.sendMessage(new StudyMessage(study, StudyStatus.OPEN););
    }

사용할 땐, 이렇게 어드바이스 내에서 넘겨받은 매개변수들을 이용해서 메시지를 마들고 만든 메시지를 messangerService에 넘겨주도록 말이죠.

이렇게.. 인터페이스를 설계하지 않고 그냥 만든 메일 서비스가 있는 상태에서 비슷하지만 조금 다른 새로운 알림 서비스.. 구글토크서비스를 추가해보니 거의 모든 부분을 새로 만들었습니다.

하지만 이번에는 인터페이스를 만들어 둔 상태에서 트위터 서비스를 추가해봤습니다. 추가하려니까 기본적인 골격이 이미 구글토크서비스와 상당히 비슷하더군요.

그래서 구글토크서비스의 인터페이스를 다음과 같이 바꿨습니다.

public interface NotificationService {
   
    void sendMessage(SpringSproutMessage ssm) throws NotificationException ;

}

노티로 바꾸고, 노티 예외를 하나 만들어서 그걸 던지도록 했습니다. smack이나 twitter4j가 checked exception을 던지는데.. 별로 뭐 예외를 잡아서 할 일이 없기 때문에 unchecked exception 계층 구조가 필요해서 저렇게 바꿨습니다.

그리고 트위터 서비스를 구현했습니다.

@Service
public class TwitterService implements NotificationService {

    @Autowired Twitter twitter;

    public void sendMessage(SpringSproutMessage ssm)
            throws NotificationException {
        try {
            twitter.updateStatus(ssm.getMessage());
        } catch (TwitterException e) {
            throw new TwitterServiceException("HTTP status code: "
                    + e.getStatusCode() + " 메시지: " + ssm.getMessage(), e);
        }
    }

}


초간단입니다. 이 클래스랑 NotificationExcpetion을 상속받은 예외 클래스를 하나 만들었습니다. SpringSproutMessage는 구글토크 서비스에서 사용하던 것을 그대로 재사용합니다.

애스팩트를 수정해 줍니다.

    @AfterReturning(pointcut = "addStudyPointcut() && args(study)", argNames="study")
    public void sendMailAfterAddStudy(Study study){
        sendMailService.sendMail(new StudyMail(study, StudyStatus.OPEN));
        StudyMessage msg = new StudyMessage(study, StudyStatus.OPEN);
        messangerService.sendMessage(msg);
        twitterService.sendMessage(msg);
    }

이렇게 됐습니다. 메일 서비스가 이 인터페이스를 따르지 않고 있는것이 좀 불만입니다. 게다가 인터페이스는 있지만 인터페이스 기반 프로그래밍이 제대로 되고 있지 않은 것 같습니다. 이건 그림으로 보면 보다 명확합니다.


이런 상태죠. MailService역시 NotificationService를 구현하도록 수정하고 MailService에서 사용하던 메시지들도 SpringSproutMessage를 상속받아 구현하게 하면 다음과 같은 구조가 될 겁니다. 그나마 다행인 것은 이메일 서비스를 만들 때 3차인가 4차 수정을 거쳐 Aspect를 빼놨다는 것입니다. 서비스 코드가 무한정 정신없어질뻔했는데 역시 Aspect로 빼내길 잘한것 같습니다.


자. 이렇게 말이죠. NotificationService 타입의 콜렉션을 가지고 해당 콜렉션을 순회하면서 메시지를 보내도록 코딩을 하면 새로운 NotifiacationService를 추가할 때마다 애스팩트를 고치지 않아도 됩니다.

간단한 빈 설정으로 콜렉션에 추가만 해주면 되죠. 이 얼마나 멋진 인터페이스 기반 프로그래밍인가요. 왜 인터페이스 기반 프로그래밍이 중요한지 몸소 체험할 수 있는 기회였습니다.

자.. 이제 설계가 끝났고 이게 훨씬 좋은 아키텍트라는 확신이 생겼으니... 비용은 좀 크겠지만, 코드를 뜯어고쳐야겠습니다.

뜯어고치는 일은.. 집에가서~~


ps: 여기서도 로컬 환경과 운영 환경 설정 분리와 구분이 필요한데, 로컬 서버에 띄우고 테스트 하느라 스터디/모임 등을 만들고 수정하면서 트위터에 잘 게시가 되나 확인했습니다. 그러나 실제로는 이 내용들이 실제 봄싹 트위터 계정이 아니라 테스트용 계정으로 만든 곳으로 올린다던지... 해야겠죠.


top

  1. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.23 20:52 PERM. MOD/DEL REPLY

    잘 바꾸셨네요.
    저게 바로 Polymorphism 이죠. :)

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.23 22:31 신고 PERM MOD/DEL

    넵 흐윽.. 집에와서 청소하고 간식좀 먹었더니.. 이제야 코딩하겠네요. 후딱 ㄱㄱ

Write a comment.


테스트 환경와 운영 환경용 설정 분리/구분하기

모하니?/Coding : 2009. 9. 23. 19:06


public class SpringSprout2System {
    public static final String ENCODING = "UTF-8";
    public static final String S2C_HOME = "http://www.springsprout.org/";
    public static final String AVATAR_URL = "http://www.gravatar.com/avatar/";
...
    public static final String JSON_VIEW = "mappingJacksonJsonView";
}


이런식으로 시스템에서 자주 사용하는 상수 값들을 모아두었습니다. 그런데 문제는 저 중에서 S2C_HOME의 값이 로컬 서버에서 돌 때랑 실제 운영 서버에서 돌 때랑 달라져야 하는데 그렇지 않고 있다는 것이었죠.

그럼 일단 프로퍼티 파일로 빼고 싶어질 겁니다. 그런데.. 프로퍼티 파일로 빼면 다인가요? 프로퍼티 파일로 빼고 그걸 빈으로 등록해서 참조해서 쓰면 끝인가요? 프로퍼티 파일이 일단 로털 테스트용/운영 서버용 이렇게 두 개로 나뉠텐데.. 그럼 로컬에서 작업할 땐 로컬용 프로퍼티 파일 쓰다가 버전 관리 올릴 때는 빼고 운영 서버용을 쓸건가요 아니면 프로퍼티 파일 하나에 모두 넣어 놓고 일부는 로컬용으로 일부는 서버용으로 해놓고 주석처리를 바꿔가며 쓸건가요??

도무지 깔끔한 방법이 아니라는 생각이 들어서 고민하다가 봄싹에서 토론도 하고 사부님이랑 전화통화 하다 생각나서 물어보기도 했습니다. 결국은 다음 세 가지 방법으로 정리가 됐습니다.

1. 프로그래밍을 이용한 설정(스마트 설정)

빈을 하나 등록해서 해당 빈이 현재 애플리케이션이 배포된 서버 환경에 대한 정보를 분석해서 이게 운영 서버인지 아닌지 판단해서 거기에 맞게 환경 변수를 샤샥 등록하는 방법입니다. 자바의 System.getProperty()에 os.name os.arch os.version 키 값을 이용해서 지금 돌고 있는 운영체제의 정보를 알 수 있습니다.

2. 설정파일을 버전관리에서 제외시키기(설정파일 외부화)

별도의 프로퍼티 파일로 배포 환경에 따라 달라지는 속성들을 빼놓고, 이 파일을 버전관리에서 제외시켜서 개별적으로 관리하는 방법입니다. 공유되지 않기 때문에 운영 서버에 초기 세팅할 때나 로컬 개발환경에서 처음 세팅할 때 설정 파일을 만들어 주거나 기본 템플릿 파일을 수정해줘야겠죠.

3. 빌드 툴을 사용하는 방법(빌드 다양화)

앤트라면 간단하게 타겟 하나를 만들어서 특정 프로퍼티 파일은 지우고 다른 걸 추가하는 식으로 운영용 타겟과 빌드용 타겟을 만들어서 쓸 수 있을 것이고, 메이븐이라면 메이븐 프로파일을 사용할 수 있겠습니다.

이 세 가지 방법 이외에도 어떤 것이 있고 어떤 방법이 좋을지 논의 중입니다.

'스마트 설정' 방식과 '빌드 다양화'는 딱 한번만 설정 해두면 계속해서 쓸 수 있기 때문에 비슷한데, 프로그래밍을 할 것이냐 빌드 설정을 할 것이냐 그것이 고민이고, '설정파일 외부화'는 프로젝트를 새로 받을 때 마다 한번씩 수고해야 하기 때문에 다른 두개 보다는 좀 더 귀찮은 것 같습니다. 하지만... 로컬 서버 환경이라고 해서 전부 다 같은 설정을 사용하진 않겠죠. 누구는 localhost:8080에 설치하고 누구는 loclahost:80을 사용할 수도 있을테니까요. 그런면에서 보면 누구나 하나씩 프로퍼티 파일을 별도로 만들게 하는 '설정파일 외부화' 방법이 가장 적절해 보입니다.

뭘 선택할지 고민이네요. 아~~~~~~ 고민이로세. 고민이야.. @_@

이것들 말고 또 다른 방법은 뭐 없을까요. 획기적으로.. 스크립트 언어를 활용한다던가, 스프링 EL을 쓴다던가...

이럴 땐 찍어서 하나 써보면 될까요? 써보다 뭔가 불편하면 다른 방법으로 갈아타고..
그렇다면, 나중에 갈아타도 시스템에 별로 지장이 없어보이는 녀석을 선택하는게 좋겠네요.

그렇다면... '설정파일 외부화' --> '빌드 다양화' --> '스마트 설정' 순으로 시도해보는건 어떨까 싶습니다.

top

  1. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.23 20:17 PERM. MOD/DEL REPLY

    저는, 사실 별 방법은 아닙니다만, 이런방법을 씁니다.
    꼭 개발 환경과 사용 환경을 구분하려는 것 이외에도
    개발중인 어플과 실제 사용중인 어플의 동작에 차이가 있을
    필요가 있을때도 쓰는 방법입니다.

    웹어플을 주로 만드니까 웹어플을 기준으로
    어플리케이션이 시작될때, 즉, 미리 만들어 놓은 ContextListener에서
    properties파일이건 XML파일이건 어플의 버전 정보가 들어가는 파일을
    확인하건 parameter 값을 가져오건 암튼 버전 정보를 확인해서
    (예. -Dev 개발버전, -GA 사용버전)
    개발 버전이면, 개발용 설정을 사용하고,
    정식 릴리즈 버전이면, 다른 설정을 사용하는거죠.

    이러면 설정파일을 바꿔치기 한다거나 전체를 다 주석 처리할 필요없이,
    버전 정보 부분만 간단하게 수정해서 환경설정 변환이 가능하니까요.
    배포전에 버전 정보 확인은 필수일테니 이거 고치는거야 일도 아니구요.

    설정파일 전체 교체나 수정보다, 버전 정보 하나 수정으로
    일을 쉽게 해결하는거죠.

    개발 서버 버전 정보가 배포 버전에 들어가는게 신경쓰이면
    배포전에 개발버전용 설정 파일만 삭제해버리면 그만 이구요.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.23 20:24 신고 PERM MOD/DEL

    오호.. 어딘가 들어있을 버전 정보를 이용해서 설정을 바꾸는 방법이로군요..

    초기에 읽어오는 그 애플리케이션의 버전 정보로 적절한 프로퍼티 파일을 읽어오도록... 으흠...

    수정할 것은 딱 하나.. 버전정보. 개발 할 때는 계속해서 개발버전으로 쓰니까.. 로컬 설정을 쓰고 서버에 배포할 때는 배포버전으로 바꿔서 배포 설정을 쓰도록..

    스마트 설정을 약간 수동적인 방법을 동원해서 좀 더 명시적으로 하는거군요.

    그럴거라면. 스마트 설정 방식에 플래스를 하나 둬서 isLocalServer 속성에 true/false 값을 보고 분기하는 빈을 만들어서 써도 되겠네요.

    좋은 아이디어입니다. 감사합니다!

  2. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.23 20:50 PERM. MOD/DEL REPLY

    위에 언급하신 1번 방법하고 크게 다르지 않은데,
    단지 구분 할때 쓰는 값으로,
    바꾸기 쉽고, 개발 버전과 사용 버전에 따라 확실히 바뀌는
    버전값을 이용한것 뿐이죠.

    제가 이 방법을 쓰게 된 계기가...
    예전에 기술 담당 부서에서 장비 교체하느라
    서버들을 다 정지 시킨적이 있는데,
    제가 만든 어플 단 하나만이 돌던
    거의 그 어플 전용인 서버를
    실수로 재실행 하지 않은겁니다.

    보스로부터 어플이 동작하지 않는다는 연락을 받고
    확인해 보니 서버가 죽은거더군요...ㅡ_ㅡ;

    그래서 기술 부서에 연락하고, 생각한게
    어플이 설치 됐을때와 제거 됐을때 이메일로 통보를 하도록하면,
    서버 정지시에 이메일이 전송될테니
    문제가 있는것을 알수 있을테고,
    설치시에도 새버전이 설치 됐다는걸 알아야 하는
    사람들에게 자동으로 알릴수 있으니 좋겠다는 거였습니다.

    그래서 ContextListener를 하나 만들고,
    그런 기능을 넣었는데...
    이게 성가신게, 개발중에 설치/제거 혹은
    Eclipse에서 context reloading이 될때마다
    메일을 전송하는겁니다...ㅡ_ㅡ;;;
    전송 되는게 당연한 얘깁니다만...

    그래서, 버전에 따라 개발 버전과 배포 버전의 설정을
    다른것을 사용하도록 하고,
    어플 동작도 일부 다르게 하도록
    만들어 버린거죠.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.23 22:30 신고 PERM MOD/DEL

    ㅎㅎ그렇군요.

    저도 이런 설정이 필요하다고 절실히 느낀게..
    이메일 전송 기능하고 관련이 있어요.

    로컬에서 테스트 할 땐 회원 가입 인증 메일이 localhost로 와야하는데 그 URL을 상수 빼기만 했더니.. 영~~~

Write a comment.


[봄싹] 매주 토요일

모하니?/그냥 놀아 : 2009. 9. 21. 01:09



이러고 지낸답니다. 스터디도 하고 개발도 하다보면 주말이 정말 금방 끝나버립니다. 주 6일 근무 하는 것과 비슷한 기분이지요. 그래도 즐겁답니다. 매번 새로 오시는 분들과 매주 조금씩 발전하는 봄싹 사이트를 보면 정말 뿌듯합니다.

매주 스터디에 나가도 불평 한마디 없이 오히려 배려해주고 신경써주는 와이프와
봄싹에 참여하여 자신의 생각과 코드를 공유해주시는 분들이 있어서 정말 즐겁습니다.

모두 즐거운 한 주 되시고 토요일에 또 뵈요.ㅋ


top

  1. Favicon of http://nije.pe.kr BlogIcon 김재진 2009.09.21 08:33 PERM. MOD/DEL REPLY

    왠지모르게 사진으로 보니 개발모임이 더 력셔리해 보이는 이유가 멀까요 ~ ㅎㅎ

    26일은 출근이라 패스 추석지나고 10일날 모임에나 갈 수 있겠네요~

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.21 10:01 PERM MOD/DEL

    ㅋㅋ사진이 이뻐서..

    ㅇㅇ10일에 봅세~

  2. Favicon of http://toby.epril.com BlogIcon 토비 2009.09.21 08:43 PERM. MOD/DEL REPLY

    불평이 없다고 자만하지 말아야...

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.21 09:33 PERM MOD/DEL

    넵.. 잘해야죠;;
    와이프랑 맛있는 쵸콜렛만 잘 골라먹고 있어요. 헤헤

  3. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.09.21 14:55 신고 PERM. MOD/DEL REPLY

    약간 굳었는데요 ;;ㅎㅎ

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.22 08:58 PERM MOD/DEL

    그런가 후훗

  4. Favicon of http://sonegy.egloos.com BlogIcon 소내기 2009.09.21 15:33 PERM. MOD/DEL REPLY

    어머 나 찍혔어--;

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.22 08:59 PERM MOD/DEL

    멋져요!

  5. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.22 14:25 PERM. MOD/DEL REPLY

    소내기님 진지함
    작히는 심각함
    그래도 뭐.. 이뻐 보이기만 하구만~공부할 때가 젤로 이쁘더라

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.22 15:43 PERM MOD/DEL

    나름대로 카메라 의식하고.. 살짝 웃고 있었는뎅; 아주 살짝...

  6. Favicon of http://www.pgone.org BlogIcon Miracle 2009.09.22 14:55 PERM. MOD/DEL REPLY

    설정의 냄새가.. 솔솔;;

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.22 15:43 PERM MOD/DEL

    ㅋㅋㅋ설정맞지요.

Write a comment.


[봄싹] 스프링 레퍼런스 3.0 번역 시작

모하니?/Koreanization : 2009. 9. 18. 00:29


http://springsprout.org/wiki/464.do

3.0 레퍼런스 번역을 꾸준히 하겠습니다. 그동안 블로그에 조금씩 번역해서 올려두기도 했었는데 아무래도 레퍼런스 글은 블로그에서 찾아보는게 불편해서 봄싹 위키에 정리하기로 했습니다.

일단은 저 혼자 시작합니다. 하지만 봄싹 회원이라면 누구나 위키 페이지를 추가/수정/이동 시킬 수 있기 때문에 자유롭게 참여하실 수 있습니다.

정해진 틀도 없고 파트를 나누지도 않았지만, 봄싹 사이트도 처음에는 이런 방법으로 개발을 시작했습니다. 지금은 제법 틀도 갖춰져 있고, 특정 모듈 또는 기능 담당자(? 라기 보단 스스로 책임을 느끼시는 분들)도 있습니다. 수직 구조로 누가 누구에게 지시하거나 일을 나눠주지 않고 수평구조로 서로 토론하며 자신이 만들고 싶은 기능을 마음대로 구현해 넣고 있습니다. 레퍼런스도 이런 방법으로 번역을 완성할 겁니다.

기여(?).. 흠. 참여하고 싶으신 분들은 언제나 대환영입니다.

파이팅!

ps: 위키 수정/추가시 포인트를 계산해서 위키 기여도를 측정해야겠군요. 가장 많이 기여한 분에게 봄싹 티셔츠라도...

ps: 위키 미리 보기 화면과 실제 화면이 좀 다른데;; 아마도 조만간 소내기형이 수정해주지 않을까 싶네요... 형 수정해주세요.. ㅠ.ㅠ


top

  1. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.09.18 01:15 신고 PERM. MOD/DEL REPLY

    번역시작한다는 말이 먼말인가 했더니...
    아~ 영어공부 제대로 한번 하겠는걸요? ㅎ

    짧은 영어실력이지만... !!
    동참하겠음.. ㅋ

    그런데 봄싹에선 아직 봄싹 티셔츠 살돈의 여유가...ㅠㅠ

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.18 09:26 PERM MOD/DEL

    아직 기여도 측정 기능 안 넣으니까 많이 해둬. ㅋㅋㅋ

  2. Favicon of http://sonegy.egloos.com BlogIcon 소내기 2009.09.21 16:13 PERM. MOD/DEL REPLY

    css좀 수정해야겠네. 알았어.ㅋ

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.22 08:59 PERM MOD/DEL

    네 이번에 디자인 바뀔때 샤샥!

Write a comment.


초고속 로보트 손

모하니?/Watching : 2009. 9. 15. 22:56




오오... 굉장하군요... 굉장해. 마지막에 핸드폰 잡는게 예술입니다.

top

TAG 로보트

Write a comment.


봄싹 9월 특강 Completed!! 후기랄까나...

모하니?/Thinking : 2009. 9. 15. 01:48



켄트벡 세미나와 KSUG 번개에 나갔었다면, 볼 수 있었겠지만 개인 사정으로 그동안 토비님을 못 뵈었다가 드디어 봄싹 스터디에 초대하여 3시간짜리 스터디 진행을 부탁드렸습니다. 커피 한 잔과 감자탕 한 끼로 너무 많이 부려먹은듯(?)해서 죄송스럽지만, 뭐.. 제자에게 이정도쯤은.. 해주셔야.. ㅎㅎㅎ 그저 감사 할 따름입니다. (__)/

이번에 사부님을 만나 느낀점은 많지만 그 중에서 개발자로서의 고민이 좀 더 심화되었습니다. 사실 다음 DebDay를 다녀왔을 때부터 느끼던 것인데 털어놓진 않고 속으로 앓고 있었지요.

문제의 핵심은 제가 작성한 코드가 개떡같다는 거였습니다.

그 개떡같은 코드는 현재 제 노트북에만 있고 그 어디에도 공개하지 않았습니다. 저번 달인가 이번 달 초에 다음 DevDay 때문에 제주도에  갔었을 때 작성한 코드가 정말 최악이었습니다. 스프링 코드를 거의 사용하지 않고 Smack과 java.net 패키지를 주로 이용하여 코드를 작성했었는데 정말 끔찍했습니다. 조금씩 계속 지져분해지기 시작하더니 어느 순간 걷잡을 수 없는 형태의 코드가 되어버렸고... 그 뒤는... 동작하긴 하지만 속은 다 썪어서 도무지 남에게 보여줄 수 없는 코드가 되었습니다.

그러던 중... 봄싹 스터디에서 스프링의 가장 기초이자 핵심은 DI가 어떤 것인지 보여주는 명쾌한 코드와 설명을 보면서 다시 한 번 자극을 받을 수 있었습니다. 스프링의 핵심인 DI가 어떤 과정으로 탄생되는 것인지 살펴보았는데, 그 과정이 굉장히 논리적이고 깔끔했습니다.

거기에다, 비밀리에 베타리딩 중인 책에서도 스프링이 어떤 문제를 어떤 방법으로 해결해나가는지 순차적으로 보여주는 내용이 저에게 많은 도움이 되고 있습니다.

스프링의 가장 초기 모습을 볼 수 있는 빨간책 1권과 코드를 중심으로 살펴보면서 스프링 DI 감각을 익히는 것이 중요하고 재밌겠다고 생각했습니다. 그래서 갑작스래 봄싹 스터디에 '오리지널 스프링' 스터디를 만들었는데, 생각보다 많은 분들이 참여하고 계십니다. 슬슬 스터디 홍보로 전환되는 듯 한데 어서 마무리하고 좀 더 공부하다 자야겠습니다.

밤늦게 글을 써서 그런지 두서가 없는데, 결론은 토비님 덕분에 스프링을 좀 더 진지하게 공부하게 되었다는 것입니다. 부디.. 개떡같은 코드가 찰떡같은 코드로 거듭나길 바라며~~ 열공!!
top

  1. 이진서 2009.09.15 08:41 PERM. MOD/DEL REPLY

    음..
    개떡같은 코드라....
    너무 겸손하신듯.. -_ㅡ;;

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.15 08:58 PERM MOD/DEL

    그 코드를 못보셔서 그래요.ㅋㅋ

  2. Favicon of https://helols.tistory.com BlogIcon is윤군 2009.09.15 09:10 신고 PERM. MOD/DEL REPLY

    공개 해봐요 ;; ㅎ

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.15 09:19 PERM MOD/DEL

    안 돼;; 그냥 그거보다 조금 덜 개판인 SES 프로젝트를 봐.. 그것만해도 충분히 고칠께 많아.

    http://whiteship.me/2328

    이번이나 다음번에는 저 코드를 스프링 스타일로 고쳐보기 할까?

    각자 엉망이라 생각하는 코드를 가져와서 스프링 스타일로 고쳐보는거지..

  3. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.15 12:26 PERM. MOD/DEL REPLY

    Debday 아니고 Devday...
    난 왜케 오타만 보일까;;;,

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.15 12:42 PERM MOD/DEL

    그렇군; dev였당.

  4. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.15 16:05 PERM. MOD/DEL REPLY

    전 스프링 소스 코드나 구글 주스 소스 코드 보고 실망한 적도 있습니다.
    뭐 실망이라기 보다 좀 충격적이었달까요?
    그거 보고... 저렇게 하면 안 좋을텐데... 하는 생각에...
    뭐 그렇다고 그 코드 짠 사람이나 프로그램 전체에
    실망한건 아닙니다.

    왜냐하면, 그 누구라도 개떡같은 코드를
    생산하는 일이 생길수 있는거고, 실수도 누구나 하기 때문이죠.
    실력이 아무리 좋고 경험이 아무리 많아도
    완벽한 사람은 없습니다.
    거기에 일정에 쫓기다 보면, 어느정도 타협해서
    좋지는 않지만 돌아가는 코드를 만드는 경우도 있겠구요.

    혹은 같이 일하는 프로그래머에게 어느정도
    돌아가는 코드를 빨리 제공해서
    그쪽에서도 일을 빨리 착수 할수 있게
    하기 위해서 우선 대충 돌아가는 코드를 만들어서
    repository에 commit 하는 경우도 있겠구요.

    전, 한참 작업중에 다른장소로 이동해서 다른컴에서
    그 작업을 이어서 할 일이 생겨서
    에러가 있는 상태의 코드를 어쩔수 없이 commit하면서
    comment에 이버전은 고쳐야 할 심각한
    에러가 있으니 절대 update하지 말라고 적어 놓은 경우도 있구요.

    아무튼 중요한건 자기 자신이 만족하지 않고,
    개선해 나가려는 의지를 가지고,
    개선하려는 노력을 해나가는것이 아닐까 싶군요.

    그런의미에서 기선님께는 잘하고 계신거 같습니다.
    지금 기선님의 코드가 정말 엉망인지 아닌지를 떠나서
    스스로 그렇게 생각하고 개선하려 한다면
    말씀하신대로 개떡이 (아니 개떡이 어때서요! 얼마나 맛있는데...ㅡ_ㅡ; )
    찰떡이 되고, 찰떡은 꿀떡이 되야 하나요?
    암튼... 언제나 발전하는 사람이 되는것이 아닐까요? :)

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.15 16:59 PERM MOD/DEL

    꿀떡같은 코드를 빠르고 정확하게 만들어 낼 수 있을 때까지 계~~~속 고고씽이요!!

    10년이 넘을지도;;;

Write a comment.


스프링 이메일 확장하기 3

모하니?/Coding : 2009. 9. 14. 14:33


아마도 이번 글이 스프링 이메일 확장하기 시리즈의 마지막이 될 것 같습니다. 이전까지 작업한 내용들을 간략히 간추리자면 다음과 같습니다.

스프링 이메일 확장하기 1 - SimpleMailMessage를 확장하는 방법.
스프링 이메일 확장하기 2 - MimeMessage, JavaMailSender, 별도의 메일 클래스 계층 구조, 이 셋을 가지고 메일을 전송하는 SendMailService를 사용하는 방법.

이번에는 SendMailService를 StudyService와 MemberService 같은 곳에 혼재되어 나타나는 것을 Aspect로 분리한 것에 대해 이야기하렵니다. (보여드리는 편이 서로 편하겠지만..)

우선 메일 서비스 때문에 불편한 점들이 속속 생기기 시작했습니다. 테스트 하기가 불편했습니다. 단위테스트야 목킹한 다음에 대충 무시해주면 그만이지만, 통합테스트일 경우 스터디나 모임 추가/변경 테스트를 할 때 마다 테스트성 메일이 전송되는데, 이 때 생기는 오버헤드와 불필요한 메일 메시지가 상당히 거슬렸습니다. 그래서 대부분 단위테스트로 바꿨습니다.

그러나 단위테스트를 한다고 해서 편해지는 것도 아니었습니다. StudyService에서 SendMailService를 사용하고 있는 이상 목킹을 하고 해당 목이 잘 동작하는지 테스트를 해야했죠. 결국 테스트 할 분량이 늘어나서 테스트를 작성할 때 귀찮았습니다. 비스무리하게 메일 전송하는 부분을 스터디, 모임 추가/변경 때마다 테스트를 목킹해줘야 했으니 말이죠.

다음은 코딩하기가 번거로웠습니다. 지금까지 메일 서비스의 큼직한 설계 변경 두 번으로 StudyService와 MemberService는 계속 고쳐져야했습니다. 아니.. 메일 전송 관련 부분을 고치는데 얘네들이 이렇게 고생을 많이 해도 되는걸까? 뭔가 잘못된거 아닌가.. 하는 생각이 들었습니다. (OCP 원칙에 위배된 코드였던게죠.)

결론은.. 그래.. 빼자.. 빼..

어떻게?

AOP!!

그래서 SendMailAspect라는 것을 하나 만들었습니다. 그리고 StudyService와 MemberService에서 참조하고 있던 SendMailService를 없애고, SendMailAspect 안으로 넣어줬습니다.

SendMailAspect에 포인트컷을 정의하고, 어드바이스를 정의해서 간단하게 메일 전송 서비스를 AOP로 구현할 수 있었습니다. 그러나 곧 또다른 요구사항이 생기기 시작했습니다.

스터디, 모임 추가/변경 할 때 트위터에 메시지를 올리자는 것이었습니다. 그리고 재버 애플리케이션을 이용해서 구글 토크로 메시지도 전송하자고 했습니다.

캬.. 멋지구나!!

아.. 이름을 바꿔야겠다. NotificationAspect로 바꾸고 그 안에 TwitterService와 GoogleTalkService를 추가하면 되겠구나!! 그래서 이름을 NotificationAspect로 수정했습니다.

@Aspect
public class NotificationAspect {
   
    @Autowired SendMailService sendMailService;
   
    @Pointcut("execution(* *..*.StudyService.addStudy(..))") void addStudyPointcut(){}
    @Pointcut("execution(* *..*.StudyService.updateStudy(..))") void updateStudyPointcut(){}
    @Pointcut("execution(* *..*.StudyService.addMeeting(..))") void addMeetingPointcut(){}
    @Pointcut("execution(* *..*.StudyService.updateMeeting(..))") void updateMeetingPointcut(){}
    @Pointcut("execution(* *..*.MemberService.add(..))") void addMemberPointcut(){}

    @AfterReturning(pointcut = "addStudyPointcut() && args(study)", argNames="study")
    public void sendMailAfterAddStudy(Study study){
        sendMailService.sendMail(new StudyMail(study, StudyStatus.OPEN));
    }

    @AfterReturning(pointcut = "updateStudyPointcut() && args(study)", argNames="study")
    public void sendMailAfterUpdateStudy(Study study){
        if(study.getStatus() != StudyStatus.ENDED)
            sendMailService.sendMail(new StudyMail(study, StudyStatus.UPDATED));
    }
   
    @AfterReturning(pointcut = "addMeetingPointcut() && args(study, meeting)", argNames="study, meeting")
    public void sendMailAfterAddMeeting(Study study, Meeting meeting){
        sendMailService.sendMail(new MeetingMail(study, meeting, MeetingStatus.OPEN));
    }

    @AfterReturning(pointcut = "updateMeetingPointcut() && args(meeting)", argNames="meeting")
    public void sendMailAfterUpdateMeeting(Meeting meeting){
        if(meeting.getStatus() == MeetingStatus.OPEN)
            sendMailService.sendMail(new MeetingMail(meeting, MeetingStatus.UPDATED));
    }

    @AfterReturning(pointcut = "addMemberPointcut() && args(member)", argNames="member")
    public void sendMailAfterAddMember(Member member){
        sendMailService.sendMail(new ConfirmMail(member));
    }
   
}


이제는 TwitterService와 GoogleTalkService만 위 애스팩트에 추가해서 넣으면 됩니다.

차후에 세미나 정보가 추가됐을 때 메시지를 보내달라는 요구사항이 생길 수도 있는데, 그 때도 위에 있는 애스팩트만 고치면 되지 세미나 서비스는 건드릴 필요가 없어졌습니다.

이렇게 좋은 점만 있었던 것은 아닙니다. 개인적으로 애스팩트를 개발할 때 가장 필요하다고 생각하는 테스트가 바로 포인트컷 테스트였는데, 그걸 못했었습니다. 어떻게 해야할지 떠오르지가 않더군요. 매번 애플리케이션을 돌려가며 확인하는것은 정말 너무 노가다이고, STS의 AspectJ 툴이 보여주는 위빙 포인트로는 만족하지 못하겠고 말이죠.

그런데.. 오늘.. 그동안 비밀리에 베타리딩 중이던 책을 읽다가 딱.. 제가 원하던 코드를 볼 수 있었습니다. 그 부분을 참조하여 포인트컷이 내가 원하는 메서드에 걸리는지 확인하는 테스트를 작성했습니다.

    @Test
    public void pointcuts() throws Exception {
        checkPointcutMatches(NotificationAspect.class, "addStudyPointcut",
                StudyService.class, "addStudy", Study.class);
        checkPointcutMatches(NotificationAspect.class, "updateStudyPointcut",
                StudyService.class, "updateStudy", Study.class);
        checkPointcutMatches(NotificationAspect.class, "addMeetingPointcut",
                StudyService.class, "addMeeting", Study.class, Meeting.class);
        checkPointcutMatches(NotificationAspect.class, "updateMeetingPointcut",
                StudyService.class, "updateMeeting", Meeting.class);
        checkPointcutMatches(NotificationAspect.class, "addMemberPointcut",
                MemberService.class, "add", Member.class);
    }

    private void checkPointcutMatches(Class<?> aspectClass,
            String pointcutMethodName, Class<?> targetClass,
            String targetMethodName, Class<?>... args)
            throws SecurityException, NoSuchMethodException {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression((String) AnnotationUtils
                .getValue(AnnotationUtils.findAnnotation(ReflectionUtils
                        .findMethod(aspectClass, pointcutMethodName),
                        Pointcut.class)));

        assertThat(pointcut.matches(targetClass), is(true));
        assertThat(pointcut.matches(targetClass.getMethod(targetMethodName,
                args), targetClass), is(true));
    }

인라인 리팩토링을 너무 많이 해서 그런지... 다소 복잡해 보이는 코드지만, 방법은 무척 간단했습니다. 단.. 테스트를 조금 편하게 하기 위해 불필요하게(여러 어드바이스에서 공용으로 사용할 포인트컷이 아님에도 불구하고) pointcut을 별도로 정의한 것이 조금 맘에 걸리기는 하지만, 그 정도는 뭐.. 애교로..ㅎㅎ 사실 더 정확하게 포인트컷을 테스트 하려면 애스팩트의 코드를 다음과 같이 바꿔야 합니다.

@Aspect
public class NotificationAspect {
   
    @Autowired SendMailService sendMailService;
   
    @Pointcut("execution(* *..*.StudyService.addStudy(springsprout.domain.study.Study))") void addStudyPointcut(){}
    @Pointcut("execution(* *..*.StudyService.updateStudy(springsprout.domain.study.Study))") void updateStudyPointcut(){}
    @Pointcut("execution(* *..*.StudyService.addMeeting(springsprout.domain.study.Study, springsprout.domain.study.Meeting))") void addMeetingPointcut(){}
    @Pointcut("execution(* *..*.StudyService.updateMeeting(springsprout.domain.study.Meeting))") void updateMeetingPointcut(){}
    @Pointcut("execution(* *..*.MemberService.add(springsprout.domain.Member))") void addMemberPointcut(){}

    @AfterReturning(pointcut = "addStudyPointcut()", argNames="springsprout.domain.study.Study")
    public void sendMailAfterAddStudy(Study study){
        sendMailService.sendMail(new StudyMail(study, StudyStatus.OPEN));
    }

    @AfterReturning(pointcut = "updateStudyPointcut()", argNames="springsprout.domain.study.Study")
    public void sendMailAfterUpdateStudy(Study study){
        if(study.getStatus() != StudyStatus.ENDED)
            sendMailService.sendMail(new StudyMail(study, StudyStatus.UPDATED));
    }
   
    @AfterReturning(pointcut = "addMeetingPointcut()", argNames="springsprout.domain.study.Study, springsprout.domain.study.Meeting")
    public void sendMailAfterAddMeeting(Study study, Meeting meeting){
        sendMailService.sendMail(new MeetingMail(study, meeting, MeetingStatus.OPEN));
    }

    @AfterReturning(pointcut = "updateMeetingPointcut())", argNames="springsprout.domain.study.Meeting")
    public void sendMailAfterUpdateMeeting(Meeting meeting){
        if(meeting.getStatus() == MeetingStatus.OPEN)
            sendMailService.sendMail(new MeetingMail(meeting, MeetingStatus.UPDATED));
    }

    @AfterReturning(pointcut = "addMemberPointcut()", argNames="springsprout.domain.Member")
    public void sendMailAfterAddMember(Member member){
        sendMailService.sendMail(new ConfirmMail(member));
    }

이전 애스팩트에서는 Advice에서 포인트컷을 다시 한 번 조합하기 때문에 실제로 어드아비스가 엉뚱한 곳에 적용된다던지.. 원하는 곳에 적용이 되지 않는 등의 문제가 발생할 수도 있습니다.

따라서, 애스팩트를 만들 때 테스트 가이드로

1. 포인트컷은 항상 @Pointcut을 이용하여 별도의 메서드로 정의하고 어드바이스에서는 포인트컷 메서드 이름만 참조하고, 조합은 하지 않는다. 조합이 필요할 때는 또 다른 @Pointcut을 정의하여 사용한다.

또는

2. 포인트컷 테스트는 어드바이스에 정의된 것을 가지고 테스트한다.

라고 정하던지 해야할 것 같습니다. 후자로 한다면 조금 복잡해지는 부분(여러 애노테이션 중에서 포인트컷 표현식을 가져오는 부분)이있어서 저라면 1번을 택할 겁니다.

Anyway!.. 이상으로 스프링 이메일 확장하기는 종료합니다. 다음에는 Twitter 서비스 만들기나 구글 토크 메시징 서비스 만들기 등의 글을 연재할지도... 바쁘면 안 할지도...


ps: 비밀리에 베타리딩 중인 책의 저자님 감사합니다. (__)/
top

Write a comment.


스프링 이메일 확장하기 2

모하니?/Coding : 2009. 9. 12. 23:52


예전에 작성했던 글에 이어지는 내용입니다. 처음부터 계획했던 글은 아니지만, 봄싹 코드가 개선될 수록 전해드리고픈 이야기도 늘어나네요.

지난 번까지의 스프링 이메일 확장에서는 한 가지 단점이 있었습니다. HTML 메시지, 첨부 파일이 있는 메일 등을 작성할 수 없다는 것이었습니다. SimpleMailMessage만을 확장한 구조기 때문이죠. 이와 같은 기능을 사용하려면 MimeMessage를 사용해야 합니다.

그런데 이 MimeMessage는 SimpleMailMessage처럼 간단하게 만들 수 있는 것이 아니라 스프링의 JavaMailSender로부터 가져와야 하는 객체입니다.

처음에는 다음과 같은 구조로 설계를 했었습니다.

MemberService {
    @Autowired JavaMailSender mailSender;
    ...
    public void addMember(Member member) {
        dao.add(member);
        sendMail(member);
    }
    ...
    private void sendMail(Member member){
        MimeMessage message = mailSender.createMimeMessage();
        ConfirmMail mail = new ConfirmMail(message, member);
        mailSender.send(mail.getMessage());
    }
}

이와 비슷한 구조들이 비밀번호를 재전송할 때도 나타났고, 스터디나 모임이 추가/변경 될 때에도 나타났습니다. 무언가 마음 한켠이 불편해지더군요.

(1) MemberService에서 메일 메시지를 만들고 보내는 것까지 관리할 필요가 없다는 판단이 들었습니다. 메일 메시지를 확장한 방법도 맘에 들지 않았습니다. (2) ConfirmMail 내부에서 MimeMessageHelper를 이용해서 MimeMessage에 필요한 정보들을 채워넣었는데 Mail에서는 Mail과 관련된 정보가 담겨야지 Mail 정보를 MimeMessage에 채우는 일은 메일을 보내는 사람의 담당이 아닐까 하는 생각이 들었습니다.

코드가 있어야 할 위치로 옮겨주는 것이 좋겠다는 생각에 설계를 바꾸게 되었고, 그결과 Mail과 관련된 모든 코드(클라이언트와 서비스까지)를 손봐야했습니다.

우선, ConfirmMail은 POJO로 to, from, content, title, isHTML 같은 속성들을 관리하도록 했습니다. MimeMessage를 꾸미는 일은 별도의 서비스 클래스를 하나 만들어서 그쪽으로 옮겼습니다. SendMailService라는 녀석이지요. 위에 표시해둔 (2)번 문제를 해결했습니다. 그리고 MemberService에서 JavaMailSender를 참조하는 대신 SendMailService를 참조하도록 했고, SendMailService.send(new ConfirmMail(member)); 이런식으로 사용할 수 있게하여 (1)번 문제를 해결했습니다. 즉, MimeMessage를 만들고, 그것을 꾸미고, 전송하는 기능을 다른곳(MemberService와 ConfirmMail)에서 가져다가 한 곳(SendMailService)로 모아뒀습니다.

그 결과 스프링 이메일을 확장한 설계도는 다음과 같이 변했습니다.


이제 별도의 메일 전송 서비스가 필요하다면, 그에 해당하는 메일관련 내용만 SpringSproutMail을 확장해서 만들면 되고, 모듈 서비스에서는 다음의 SendMailService를 이용해서 해당 메일을 send()에 넣어주기만 하면 됩니다. HTML 메시지를 보내는 SendMailService 코드는 다음과 같습니다. 이 클래스는 차후에 첨부파일 등을 추가한 메시지를 보낼 때 다시 수정 될 듯 합니다.

@Service
public class SendMailService {
   
    @Autowired JavaMailSender mailSender;

    public void sendMail(SpringSproutMail mail) {
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message, SpringSprout2System.ENCODING);
        try {
            helper.setTo(mail.getTos());
            helper.setFrom(mail.getFrom());
            helper.setSubject(mail.getSubject());
            helper.setText(mail.getContent(), mail.isHTML());
        } catch (MessagingException e) {
            throw new MailPreparationException(e);
        }
        mailSender.send(message);
    }

}

한가지 의문은 MimeMessageHelper에서는 왜 MailException이라는 RuntimeException 계층 구조를 만들어 놓고도.. 그걸 사용하지 않았느냐 입니다. 코드도 유겐이 작성한거라 뭔가 이유가 있을법한데 말이죠. 뭔가를 복구할 만한 일을 해야 한다고 생각한걸까요? 흠.. 귀찮습니다. 그냥 MailException 계층구조를 사용해서 던져줬으면 try-catch 안해도 될텐데. 일단은 잡아서 MailException의 하위 클래스 중 하나인 MailPreparationException으로 감싸서 다시 던져줬습니다.

이후에도.. 한가지 더 개선한 점이 있는데 그것은 다음에~

top

Write a comment.


[하이버네이트] 쿼리를 수정할 것이냐 모델을 수정할 것이냐...

모하니?/Coding : 2009. 9. 10. 18:17


이전에 올렸던 글에서 고민했던 것을 오늘에서야 처리했습니다.

SQL로 원하는 데이터를 가져올 것이냐(성윤이 제안).. 모델을 수정해서 로직으로 모델의 값들을 변경할 것이냐(내 생각) 중에서 결국은 제 생각을 따르기로 했습니다.

일단 시도는 SQL을 시도했습니다. 그러나 바로 단점이 생기더군요.
- 비슷한 쿼리가 있었는데 그것도 고쳐야 합니다. 비슷한 문장이 중복되는 쿼리가 여러 개 생기겠더군요.

이 문제는 DetachedCriteria를 사용해서 어느 정도 손불 수 있는 문제입니다.
- 쿼리 중에 비슷한 부분을 DetachedCriteria로 분리해두고 재사용하면 되거든요.

하지만 기술적인 문제가 기다리고 있었습니다.
- Criteria.setProject()에 넘겨주는 Proejction과 Criteria.setResultTransformer()가 예상한대로 동작하질 않았습니다.

        c.setProjection(Projections.projectionList()
            .add(Projections.property("id").as("id"))
        );
        c.setResultTransformer(new AliasToBeanResultTransformer(Study.class));

이건 잘 맵핑 해주는데..

        c.setProjection(Projections.projectionList()
            .add(Projections.property("id").as("id"))
            .add(Projections.property("name").as("name"))
        );
        c.setResultTransformer(new AliasToBeanResultTransformer(Study.class));

이렇게 하나 이상의 Projection이 추가되면 c.list()를 호출할 때 타입 캐스팅 에러가 발생합니다. 이걸 결국은 해결하지 못해서;;

마음 편하게 모델을 수정하기로 했습니다.
- 모델에 필요한 필드를 추가하고..
- xxxService에서 모임이나 멤버가 추가/삭제 될 때 로직을 추가하고.
- 테스트로 호가인하고.
끝~

이렇게 간단한 것을 쿼리 길게 작성하고, 쿼리 분리하고, DTO 만들고, 컨트롤러, 서비스, DAO 다 고치고;; 하는 것 보단 편한 것 같습니다.

top

Write a comment.


완전 부럽다...

모하니?/Thinking : 2009. 9. 9. 06:59


연봉 5천. 제네시스 지급. 몇 년뒤 벤츠로 바꿔줌. 상여금은 연간 두 번 800%. 매달 기름값 100만원 지급. 기타 등등등...

매달 순수 월급만 세금떼고 350은 넘게 받으실 텐데, 그거의 800%를 일년에 두 번이나 받으시면 제가 1년에 버는 돈보다 많은 돈을 보너스로 받으시는 겁니다. 거기에 매달 기름값을 하라고 100만원씩 받으신다면.. 와우... *_*

가까우신 분의 최근 입사 조건입니다. 저것보다 더 좋은 조건으로 일하고 계신 분들도 많이 있겠죠? 저는 개발자로서, 어찌하면 저 만큼의 대우를 받을 수 있을까요? 어떻게 하면 저만큼 회사에 필요한 사람이 될 수 있을까요? 제가 요즘 활동하며 공부하는 것들이 미래에 저런 대우를 받을 수 있는 행위일까요? 아니면 나 자신을 위안하려는 행위들에 불과한 걸까요?

저는 어떤 길을 가고 있는 걸까요? 무슨 길이든 좋으니... 지금처럼 하고 싶은 공부 마음껏 할 수 있고, 공부한 걸 적용해볼 수 있고, 주말이면 다른 개발들과 만나서 즐겁게 공부도 하고 개발도 할 수 있고, 늦지않게 집에가서 와이프랑 놀 수 있으면서도... 미래에 가질 자식들 육아비용 걱정없이, 공기 좋고 물 좋은 곳에서, 대 여섯 식구가 오손도손 살 수 있으면 좋겠습니다.

나한텐 언제 해가 뜰까?? 내일? 매일 같이 '내일' 해가 뜨는건 아닐가?
top

  1. Favicon of http://spadework.co.kr/ BlogIcon Spadework 2009.09.09 07:35 PERM. MOD/DEL REPLY

    이야... 정말 부럽삼...
    난 연봉을 100만원 더 받느냐 마느냐 하는 문제로 피터지는 중인데...
    그 분이랑 친해지고 싶어요~ ㅎㅎ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.09 13:36 신고 PERM MOD/DEL

    네. 세상엔 여러 차원이 존재하는 것 같아요.

  2. Favicon of http://nije.pe.kr BlogIcon 김재진 2009.09.09 08:11 PERM. MOD/DEL REPLY

    정말 입이 떡 벌어지게 만드는 입사조건이네요 -_-;

    어떤분에 어떤회사인지 궁금해집니다. 정말 저런 대우를 해줄만큼 회사에 필요한 인재라는것. 그걸

    인정받았다는 뿌듯함도 크겠어요..

    열심히 해야겠네요 ㅎㅎㅎ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.09 13:38 신고 PERM MOD/DEL

    대기업이지머 자세한건 비밀이라.. 오프라인에서.ㅋㅋ

  3. Favicon of http://blog.outsider.ne.kr BlogIcon Outsider 2009.09.09 10:17 PERM. MOD/DEL REPLY

    너무 파격적인 조건이라 어떤일을 하시는 분인지 궁금하기까지 하군요.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.09 13:43 신고 PERM MOD/DEL

    저도 자세히는 몰라서요.ㅋ

  4. Favicon of http://helols.pe.kr BlogIcon 성윤 2009.09.09 11:00 PERM. MOD/DEL REPLY

    형 .. 나 너무 부러워 말아요 ;;ㅋㅋ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.09 13:44 신고 PERM MOD/DEL

    ㅎㅎㅎ너였던거야?

  5. 나그네 2009.09.09 11:24 PERM. MOD/DEL REPLY

    와우~! 정말 대단한데요~!.

    이분은 개발자 신가요?

    국내에 개발자가 저런 대우를 받고 다니는 회사가 있는 건가요?

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.09 13:44 신고 PERM MOD/DEL

    개발자는 아니십니다.
    전혀 다른 직종입니다.

  6. 가리한남 2009.09.09 13:15 PERM. MOD/DEL REPLY

    로또1등보다 부러운걸?ㅎㅎ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.09 13:44 신고 PERM MOD/DEL

    난 로또도 부러워.

  7. 2009.09.09 14:03 PERM. MOD/DEL REPLY

    비밀댓글입니다

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.10 09:44 PERM MOD/DEL

    네.. 격려 감사합니다. 역시 돈 보다는 건강이.. 최고인 것 같아요.

    돈은 조금 쪼들려도 좋으니까 가족 모두 건강하면 좋겠습니다.

  8. Favicon of http://sonegy.egloos.com BlogIcon 소내기 2009.09.09 23:56 PERM. MOD/DEL REPLY

    연봉은 대기업 박사급특채면 가능하겠지만(여러가지 많겠찌?), 상여금및, 기타등등은 딱 눈돌아가네.
    돈이 돈을 버는 직업혹은 그사람 하나 들어가면 먼가 되는 그런거겠지만.
    글쎄다. 쩝. 어쨌든 나와는 거리가 너무 멀어서 뭐라 말도 못꺼내겠네~

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.10 10:31 PERM MOD/DEL

    차를 준다는 시점에서 이미 게임은 끝난듯;;

  9. 헝그리머신 2009.09.10 02:42 PERM. MOD/DEL REPLY

    .. 제 생각엔 그냥 한국에선 IT 종사하시는분들은 타당안 대우를 못받는듯.. 쩝..... .... ....

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.10 10:38 PERM MOD/DEL

    IT 뿐만 아니라 한국 모든 산업에서 가치평가가 제대로 안 되는 것 같아요.

    덜 받아도 되는 분들이 많이 받고, 더 받아도 되는 분들이 적게 받고..

    에어콘 빵빵 나오는 사무실에서 편하게 인터넷 서핑이나 좀 하다가 퇴근하는 사람보다, 새벽이나 오밤중에 쓰레기 수거하시는 분들이 더 많은 돈을 받는 날이 한국에 올까요??

  10. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.10 17:50 PERM. MOD/DEL REPLY

    너무 좌절하거나 부러워 하진 마세욤!

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.10 18:08 신고 PERM MOD/DEL

    부럽긴한데.. 그렇다고 좌절할 건 없자나ㅋㅋ

  11. Favicon of http://okjsp.tistory.com BlogIcon kenu 2009.09.12 00:24 PERM. MOD/DEL REPLY

    비담인가? ^^;

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.12 09:29 PERM MOD/DEL

    비담이 뭔지 몰라서 검색해봤더니;;
    귀족이군요.ㅋㅋ

Write a comment.


[하이버네이트] 1 + 2N select 문제 해결하기

모하니?/Coding : 2009. 9. 8. 14:30


죄송합니다. 낚시입니다. 1 + 2N select 문제 같은건 없습니다. ;-)

1+n select 문제라는 것이 있고 이것을 해결하는 여러 fetching 방법(batch, subselect , join)을 하이버네이트가 제공해줍니다.

1+n select 문제가 무엇이냐면, Study에서 1 대 다 관계로 Meeting을 참조한다고 했을 때, Study가 가지고 있는 Meeting 컬렉션은 기본값으로 Lazy 로딩이 적용됩니다. 즉, Study를 가져올 때 Meeting 컬렉션을 가져오지 않았다가.. 나중에 필요해지는 순간에 Meeting 목록을 가져옵니다.

이때, Study 전체 목록을 가져온 다음 각각의 Study에 들어있는 Meeting 목록도 가져와서 화면에 보여준다고 해보죠. OSIV 필터를 적용해뒀기 때문에 컨트롤러에서는 단순히 Study 목록만 넘겨줬지만, 화면에서는 c:foreach 구문으로 study.getMeetings()를 호출할 때 lazy 로딩을 하게 되어있습니다.

어떻게 될까요?

스터디 목록이 2개라고 해보죠.
- 전체 스터디 목록을 가져오는 쿼리를 날립니다.(컨트롤러에서)
- 첫번째 스터디의 전체 모임 목록을 가져오는 쿼리를 날립니다.(뷰에서)
- 두번째 스터디의 전체 모임 목록을 가져오는 쿼리를 날립니다.(뷰에서)

스터디 목록이 3개라고 해보죠.
- 전체 스터디 목록을 가져오는 쿼리를 날립니다.(컨트롤러에서)
- 첫번째 스터디의 전체 모임 목록을 가져오는 쿼리를 날립니다.(뷰에서)
- 두번째 스터디의 전체 모임 목록을 가져오는 쿼리를 날립니다.(뷰에서)
- 세번째 스터디의 전체 모임 목록을 가져오는 쿼리를 날립니다.(뷰에서)

이래서 1+n 문제라고 하는 겁니다. 그럼 이걸 어떻게 해결할 수 있을까요?
1. 처음으로 어떤 스터디의 모임 목록을 가져올 때, 특정 갯수 만큼의 스터디와 연관되어 있는 목록을 다 가져옵니다. => prefatching data in batches, @BatchSize
2. 처음으로 어떤 스터디의 모임 목록을 가져올 때, 로딩되어 있는 모든 스터디와 연관되어 있는 모든 모임 목록을 다 가져옵니다. => subselect fatchting, @Fetch(SUBSELECT)
3. 스터디를 가져올 때, 해당 스터디와 관련된 모임 목록도 미리 전부 가져옵니다. => eager fetching, @OneToMany(fetch=FetchType.EAGER)

이정도까지가 기본적인 하이버네이트 패칭 이야기이고, 제가 지금 겪고 있는 문제는 다음과 같습니다. 사실 이제부터가 본론이죠.

1+2N 문제가 어떻게 발생했냐면...

모든 스터디 목록을 가져오는데, 그 때 각 스터디에 참여한 회원수와 총 모임수를 가져와야 합니다.
- 모든 스터디 목록 select
- 모든 회원 수 or 목록 select
- 모든 모임 수 or 목록 select

스터디 모델에 memeberCount나 meetingCount 같은 속성은 없습니다. 스터디 목록 갯수가 20개가 된다면 select 문은 41개가 됩니다. 끔찍한 상황이죠. 갈 수록 성능이 안 좋아질 겁니다. 대책이 필요합니다. 위에서 살펴봤던 패칭 전략 중 어떤 것을 적용해 볼까요?

1. subselect fetching

어차피 모든 스터디가 가지고 있는 모든 멤버와 모임 목록을 가져와야 한다면, 굳이 배치 사이즈를 줘서 일부만 가져올 필요가 없어보입니다. 이럴 바엔 그냥 subselect fetching을 하는게 좋겠습니다.

...
    @ManyToMany
    @Fetch(FetchMode.SUBSELECT)
    private Set<Member> members;
    @OneToMany(cascade={CascadeType.ALL}, mappedBy="study")
    @Fetch(FetchMode.SUBSELECT)
    private Set<Meeting> meetings;
...

스터디 도메인에 위와같이 subselect fetching을 적용했습니다. 제가 원하는 결과는 다음과 같습니다.
1. 모든 스터디 가져오는 select
2. 모든 스터디에 대한 모든 사용자 select
3. 모든 스터디에 대한 모든 모임 select
이렇게 세 줄만 나오는 겁니다. 1+2n 에서 3으로 쿼리가 줄어들어야 합니다.

하지만, 무슨 이유에선지 제대로 동작하지 않습니다.

구글링을 해보니 subselect가 되지 않는다는 글들이 검색되는데 해결책은 마땅히 보이지가 않습니다. JPWH책을 다시 뒤젹여 봐도 설정은 위에서 추가한 애노테이션 하나 밖에 없습니다.

이게 뭔가.. @_@.. 흠 그렇다면 batch fetching을 해보지뭐..

2. batch fetching

... 
    @ManyToMany
    @BatchSize(size=10)
    private Set<Member> members;
    @OneToMany(cascade={CascadeType.ALL}, mappedBy="study")
    @BatchSize(size=10)
    private Set<Meeting> meetings;
...

자 이렇게 설정해뒀습니다. 정확한 쿼리 갯수는 BatchSize와 전체 row수와 하이버네이트의 batch-fetching d알고리즘에 따라 달라지겠지만 쿼리 갯수는 위와 비슷하거나 조금 더 많아 질 겁니다.
1. 모든 스터디 가져오는 select
2. 일부 스터디에 대한 모든 사용자 select
3. 일부 스터디에 대한 모든 모임 select
4. 일부 스터디에 대한 모든 사용자 select
5. 일부 스터디에 대한 모든 모임 select

대략 3 + 2n/10 정도로 줄어들 것으로 예상됩니다.

오예! 잘 동작합니다. 배치 사이즈 때문인지 딱 세 줄의 select로 이전에 보여주던 화면을 그대로 보여줬습니다. 다시 한 번 클릭했을 때는 어제 Study에 적용해둔 2차 캐쉬 때문에 두 번의 select가 날아갔습니다. 그 두 녀석에도 read-write로 캐쉬를 적용하면 이제 두 번째로 스터디 화면을 보여줄 때 커밋된 것이 없다면 아무런 쿼리도 날아가지 않을 겁니다. 일단은 논외기 때문에 패칭 정리를 끝낸 다음에 해보도록 하죠.

3. eager fetching

쿼리 세 줄도 아깝다!! 애초에 모든 스터디 목록으르 가져올 때, 멤버과 모임 목록도 같이 가져오도록 하고 싶다면 eager fetching을 써야겠죠.

1. 모든 스터디 목록을 가져올 때 모든 모임과 멤버 목록까지 select

1+2n이 1로 줄어듭니다. 최고네요.

...
    @ManyToMany(fetch=FetchType.EAGER)
    private Set<Member> members;
    @OneToMany(cascade={CascadeType.ALL}, mappedBy="study", fetch=FetchType.EAGER)
    private Set<Meeting> meetings;
...

오.. 원하던대로 쿼리가 하나만 날아갔습니다. 그런데!!! left outer join으로 인해서 study 목록이 원하던 것 보다 훨씬 많아졌습니다. study만 보자면 중복 데이터입니다.

못쓰겠네요. 지금까지 해본결과 두 번째에 시도한 batch fetching이 제일 적당히 잘 동작했습니다. subselect fetching이 제대로 동작해 줬다면 더 좋았을텐데 조금 아쉽네요.

4. 모델 고치기

저는 사실 패칭을 적용해보기 전에 날아가는 쿼리를 보고서 스터디 목록을 뿌리는데 모임하고 멤버는 왜 가져오는걸까;; 하면서 컨트롤러를 봤더니 스터디 목록만 줍니다. 뭐지? 그럼 어디서 쿼리가 날아가는거야??;; 뷰인가? 하고 봤더니 빙고.. OSIV 때문에 잘 보이지 않는곳(뷰)에서 쿼리가 날아가고 있었던 겁니다. 왜그런가 봤더니 바로 모임 총 갯수와 멤버 총 수를..

study.getMembers().size();
study.getMeetings().size();

이런식으로 가져오고 있었습니다. getM~~s()를 할 때 마다 뷰에서 쿼리가 날아가고 있었던 거죠. 필요한건 size인데 굳이 저렇게 멤버와 모임 목록을 가져올 필요가 있을까 싶었습니다. 그렇다고 member와 meeting의 count를 가져오자니.. 그것도 역시 SQL 한줄씩이니까 1+2n이 쿼리만 바뀔 뿐이지 여전히 1+2n이구나.. @_@..
모델을 고치자.

Study에 memberCount와 meetingCount를 추가하고
각각 스터디에 참가신청/탈퇴할 때 memberCount를 증가/감소 시키고
모임이 추가/삭제 될 때 마다 meetingCount을 증가/감소 시키자.

그러면 화면에서는

study.getMemeberCount();
study.getMeetingCount();

이렇게 호출하면 되니까 연관관계 탈 것도 없고, Lazy 로딩할 것도 없고.. 쿼리도 안날아가고..

1+2n에서 1로 줄일 수 있겠구나.. 하고 생각했었습니다. 그런데....

5. 생짜 SQL

봄싹에서 화면 디자이너겸 SQL 튜닝 전문가이자 스프링 개발자로 활약중인 성윤군이 이를 보다 못해 SQL 하나를 직접 작성해 주었습니다.

1. 모든 스터디 정보와 모임 갯수, 멤버 수를 같이 서머리 해옵니다.

select
study.id, study.studyname, study.status,
(select count(*) from study_member as sm where sm.studies_id = study.id) as member_cnt,
study.maximum,
(select count(*) from meeting as meeting where meeting.study_id = study.id) as meeting_cnt,
study.startday,study.endday
from study as study

오호.. 무척 간단했군요. 이것도 역시 1+2n을 1로 줄여주는 방법이고, 모델을 수정하지 않아도 됩니다.
대신 DTO가 하나 필요합니다. 단순히 Study 정보만 담고 있는것이 아니라 Study 도메인 객체 리스트로 화면에 넘겨줄수가 없습니다.

결국은 "DTO가 하나 늘어난다 VS 모델을 수정한다" 이 것이 고민입니다. 패칭이 적절한 경우였다면 패칭으로 해결했을 텐데 지금 여기서는 count만 하면 되지 실제로 모임과 멤버 목록을 다 가져올 필요는 없거든요.

일단은 SQL도 짜준 성윤이를 생각해서 마지막 방법을 적용해봐야겠습니다. 대신 이 쿼리를 그대로 하이버네이트로 날려도 되지만 좀 더 객체지향 적인 형태로 Criteria나 HQL을 써서 표현해볼까 합니다.

과연~ 도메인 모델에 속성 두 개 추가하고 모임 추가/삭제, 멤버 가입/탈퇴 할 때 코드를 조금 수정하는 것보다 편할 것인가~~


top

  1. Favicon of http://helols.pe.kr BlogIcon 성윤 2009.09.08 16:28 PERM. MOD/DEL REPLY

    저쿼리로 .. ㅎㅎ 빨랑 Criteria 제작 해봐요 ..ㅋ
    study 에 .. 가입한맴버수 와 모임수 를 추가해주고. ( 결국 스터디의 부가정보쯤 .. 되겠네요.. )

    Criteria를 잘 이용해서 쿼리를 날리면 좀 깔삼해지지 않을까 생각해봣어요 ..

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.08 20:23 PERM MOD/DEL

    저거 만드는건 쉬워. Criteria랑 Projection 이용하면 돼. 직접 해바바.

    그런데.. 문제는 Criteria.setResultTransformer()이거랑 list()가 뭔가 잘 안 맞는지 잘 안 되더라고;; @_@ 삽질 한 참하다 왔네;; 내일은 힘들것 같고 내일 모래나 다시 해봐야지

  2. Favicon of http://jjaeko.tistory.com BlogIcon 째코 2009.09.08 22:52 PERM. MOD/DEL REPLY

    하이버네이트 잼있는데...
    전 다 까먹었네요;;

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.09 06:27 PERM MOD/DEL

    다시 보시면 기억이 솔솔~ 나실듯.

Write a comment.


[hamcrest] Matcher 만들기

모하니?/Coding : 2009. 9. 7. 10:59


hamcrest는 Mockito와 JUnit 등 테스트 관련 프레임워크에서 참조하는 라이브러리로, Matcher라는 개념을 제공해줍니다. 이것을 사용해서 테스트를 좀 더 간편하게 만들 수 있습니다.

예를 들어, 다음과 같은 테스트가 있습니다.

ConfirmMailTest

...
        Member member = new Member();
        member.setEmail("keesun@mail.com");
        member.setName("keesun");
        ConfirmMail mail = new ConfirmMail(member);
        assertThat(Arrays.asList(mail.getTos()), hasItem("keesun@mail.com"));
        assertThat(mail.makeMessage(), containsString("회원 인증 메일 입니다"));
        assertThat(mail.getFrom(), is("s2cmailer@gmail.com"));
        assertThat(mail.getSubject(), containsString("keesun"));
...

이 테스트에서 필요한 Matcher로 isAbout(Membe member)라는 것을 하나 만들고 다음과 같은 클래스를 정의합니다. 아. 그전에 위 테스트 코드를 미리 다음과 같이 수정해 두는 것이 좋겠습니다.

        Member member = new Member();
        member.setEmail("keesun@mail.com");
        member.setName("keesun");
        ConfirmMail mail = new ConfirmMail(member);
        assertThat(mail, isAbout(member));

그런다음 클래스를 정의합니다. 이 클래스는 Mockito의 ArgumentMatcher 클래스를 상속 받고, isAbout이라는 static 메서드를 제공해줍니다.

public class MailMatcher extends ArgumentMatcher<SpringSproutMail> {

    private String from;
    private String to;
    private String subject;
    private String message;

    public MailMatcher(String from, String to, String subject, String message) {
        super();
        this.from = from;
        this.to = to;
        this.subject = subject;
        this.message = message;
    }

    @Override
    public boolean matches(Object mail) {
        SpringSproutMail smail = (SpringSproutMail) mail;
        if (from != null && !from.equals(smail.getFrom()))
            return false;
        if (!Arrays.asList(smail.getTos()).contains(to))
            return false;
        if (!smail.getSubject().contains(subject))
            return false;
        if (!smail.makeMessage().contains(message))
            return false;
        return true;
    }

    public static Matcher<SpringSproutMail> isAbout(Member member) {
        return new MailMatcher(SpringSproutMail.SENDER_MAIL, member.getEmail(),
                member.getName(), "회원 인증 메일");
    }

}

배보다 배꼽이 큰거 아닌가 하는 생각이 들지만, 이 매처 클래스를 여러 메일 테스트에서 사용할 수 있도록 조금 손을 본다면 쓸만할 겁니다.

top

Write a comment.


[GenericDao] 하이버네이트 GenericDao

모하니?/Coding : 2009. 9. 4. 15:23


먼저, GenericDao를 만들어 쓰면 좋은 이유를 생각해보겠습니다.
- 모든 DAO에서 중복되거나 반복되는 코드를 상당량 줄일 수 있습니다.
- 테스트도 그만큼 줄일 수 있습니다.
- 개발이 좀 더 빨라집니다.
- 비슷한 기능을 하는 메서드 이름을 통일할 수 있습니다.

Entity 당 DAO를 쓰면 좋은 점과 타입-안정성을 제공하는 DAO 패턴을 사용하면 좋은 점 등은 이 글에 정리되어 있으니 궁금하신 분들은 참고하세요

TDD로 다 만든 다음, 맨 마지막에 이클립스 리팩터링 기능 중에 extract interface로 뽑아 낸 인터페이스는 다음과 같습니다.

public interface GneericDao<E> {

    void add(E entity);

    List<E> getAll();

    E getById(Serializable id);

    void delete(E entity);

    void update(E entity);

    void flush();

    E merge(E entity);

}


이것을 구현한 실제 DAO 구현체는 이렇게 생겼습니다.

public class HibernateGenericDao<E> implements GneericDao<E> {

    protected Class<E> entityClass;

    @SuppressWarnings("unchecked")
    public HibernateGenericDao() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        Type type = genericSuperclass.getActualTypeArguments()[0];
       if (type instanceof ParameterizedType) {
         this.entityClass = (Class) ((ParameterizedType) type).getRawType();
       } else {
         this.entityClass = (Class) type;
       }
    }

    @Autowired
    protected SessionFactory sessionFactory;

    public void add(E entity) {
        getCurrentSession().save(entity);
    }

    private Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

    @SuppressWarnings("unchecked")
    public List<E> getAll() {
        return getCurrentSession().createCriteria(entityClass)
                .list();
    }
   
    @SuppressWarnings("unchecked")
    public E getById(Serializable id){
        return (E) getCurrentSession().get(entityClass, id);
    }
   
    public void delete(E entity){
        getCurrentSession().delete(entity);
    }
   
    public void update(E entity){
        getCurrentSession().update(entity);
    }
   
    public void flush(){
        getCurrentSession().flush();
    }
   
    @SuppressWarnings("unchecked")
    public E merge(E entity){
        return (E) getCurrentSession().merge(entity);
    }

}

특징이라고 할 수 있는 걸 꼽자면..
- 하이버네이트 SessionFactory를 사용하는 GenericDAO 라는 것.
- 별도로 엔티티 타입을 인자로 넘겨줄 필요가 없다는 것.
- 타입-안전성을 보장하기 때문에 별도의 캐스팅 등이 필요없고, 컴파일 시점에 체크 가능하다는 것.

이 클래스는 다음과 같은 테스트 클래스를 이용해서 TDD로 만들었습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="/testContext.xml")
@Transactional
public class HibernateGenericDaoTest extends DBUnitSupport{

    @Autowired TestDao dao;
   
    @Test
    public void add() throws Exception {
        TestDomain entity = new TestDomain();
        dao.add(entity);
        assertThat(dao.getAll().size(), is(1));
    }
   
    @Test
    public void getAll() throws Exception {
        insertXmlData("testData.xml");
        assertThat(dao.getAll().size(), is(2));
    }
   
    @Test
    public void getById() throws Exception {
        insertXmlData("testData.xml");
        assertThat(dao.getById(1).getName(), is("keesun"));
    }
   
    @Test
    public void delete() throws Exception {
        insertXmlData("testData.xml");
        TestDomain entity = dao.getById(1);
        dao.delete(entity);
        assertThat(dao.getAll().size(), is(1));
    }
   
    @Test
    public void update() throws Exception {
        insertXmlData("testData.xml");
        // entity is (similar)detached object
        TestDomain entity = new TestDomain();
        entity.setId(1);
        entity.setName("whiteship");
       
        dao.update(entity);
        // now, entity has been persistent object
        entity.setName("helols");
        dao.flush();
        assertThat(dao.getById(1).getName(), is("helols"));
    }
   
    @Test
    public void merge() throws Exception {
        insertXmlData("testData.xml");
        // entity is detached object
        TestDomain entity = new TestDomain();
        entity.setId(1);
        entity.setName("whiteship");
       
        TestDomain newEntity = dao.merge(entity);
        // newEntity is persistent object, but entity is still detached object
        newEntity.setName("helols");
        entity.setName("nije");
        dao.flush();
        assertThat(dao.getById(1).getName(), is("helols"));
    }
   
}

이 테스트의 특징은 다음과 같습니다.
- 하이버네이트의 update()와 merge()의 특징과 그 차이점을 이해할 수 있도록 작성했습니다.
- 스프링 테스트 컨텍스트를 사용했습니다.
- DBUnit과 그것을 확장한 클래스를 이용했습니다.


생각해볼 것
- GenericDao에 있는 update(), merge(), flush()는 Generic하지 않다는 생각이 듭니다.
- (위에는 보여드리지 않았지만)테스트에 사용된 TestDomain 클래스와 TestDao를 GenericDaoTest 내부에 포함 시키는 것이 좋치 않을까?
- 어떤 기능을 더 추가할 수 있을까?


top

  1. 대한민국토리 2009.09.04 16:29 PERM. MOD/DEL REPLY

    저도 최근에 비슷하게 기본 CRUD에 대해서 제네릭으로 인터페이스를 만들었는데요. 너무나 비슷해서 깜짝 놀랐어요. 사람들 생각하는게 비슷하구나 하구요^^

    게다가 자세한 설명에 TDD까지 덧붙여주시니 그야말로 감동입니다.

    Favicon of http://whiteship.me BlogIcon 기선 2009.09.04 17:18 PERM MOD/DEL

    네ㅎㅎ GenericXXX 인터페이스 내용은 많이들 비슷할 것 같아요.

  2. hoyeol 2009.09.04 17:33 PERM. MOD/DEL REPLY

    오.. 비슷합니다.
    제경우는 update() 를 사용할때 문제가 있어서 note에 적어두었었는데.. 내용인즉슨
    findXXX() 로 instance를 가져온후, 동일한 ID를 가진 새로운 instance를 생성해서 update()를 호출하는 경우에 NonUniqueObjectException이 발생했었습니다.
    hibernate에 대한 무지로 인해 비롯된 문제였었죠 -.-; 그래서 이후에는 반드시 update()에 "원래 가져온 instance를 다시 저장해야한다" 를 떠올리게됩니다;

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.04 22:05 신고 PERM MOD/DEL

    응~ LazyInitializing뭐시기랑 더불어 익숙해져야 하는 에러 중 하나로군..

  3. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.09.05 03:09 PERM. MOD/DEL REPLY

    저도 제가 쓰는 GenericRepository 를 예로 포스팅 하나 해야 하는데,
    여러가지 일이 겹쳐서 바빠지니, 엄두가 나질 않습니다... @_@;
    아무래도 게을러서겠죠? ㅠ_ㅠ

    그러고 보면, 쓰리잡 시작하신 기선님께서는 정말 부지런 하신듯...
    그나저나 E getById(Serializable id); 요거 id를 그냥 Serializable 로 잡으면,
    Serializable를 implements 한 타입은 다 적용되서
    실제로 쓰려는 id 타입이 아닌걸 넣어도 compile-time error가
    발생하지 않는 문제가 있을것 같은데요.

    실제 ID는 Integer인데 Long이 들어갈수도 있겠고 아니면 Double이라던가요.
    심한경우 Serializable implements한 일반 JavaBean까지 id로 들어갈수가...
    물론 id로 JavaBean을 넘기는건 심각한 실수겠지만요.
    add method같은거랑 착각해서 그냥 넣어도 컴파일 타임 에러 없음이니... 덜덜덜...
    제생각엔 역시 ID도 generic으로 잡아주는게 좋지 않을까 합니다만...

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.05 07:16 PERM MOD/DEL

    아... 그런 문제가 있군요. 키 타입이 안전하지 않았네요.
    흠.. 그래서 키 타입을 따로 주는 코드들이 있었던 거군요.

    감사합니다~ㅎㅎ

Write a comment.


[Generic] 자바 Generic 타입 알아내기

모하니?/Coding : 2009. 9. 4. 14:35


참조: http://blog.xebia.com/2009/03/09/jpa-implementation-patterns-data-access-objects/

GenericDao를 만들다 보면, entity 클래스 타입이 필요하게 되는데, 이 타입을 구하기 위해 GenericDAO를 상속받을 때 마다 생성자에서 넘겨주거나, abstract 메서드로 entity 클래스를 세팅하도록 강제하기도 하기도 하고, 저 같은 경우는 DAO 이름 컨벤션에 따라 도메인 이름을 추측하여 Class.forName()으로 자동으로 인식할 수 있게 한적도 있습니다.

일단, 전자의 방법들은 GenericDAO를 상속받는 클래스를 만들 때 귀찮다는 단점이 있습니다. 맨 마지막 방법은 컨벤션을 따르지 않았을 경우 난감해진다는 문제가 있습니다.

그러나... 이 방법들 보다 더 좋은 방법이 있었습니다.

자바 Generic 타입 정보는 흔히들 런타임에 활용할 수 없다고 알고 계실겁니다. 그건 객체들 얘기이고, 모든 객체가 지니고 있는 클래스(.class)에는 해당 정보가 남아있습니다. 따라서 런타임 때도 리플렉션을 이용해서 Generic 정보를 활용할 수 있습니다.

http://whiteship.me/1614

    @PersistenceContext
    protected EntityManager entityManager;
 
    public JpaDao() {
        ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
        this.entityClass = (Class<E>) genericSuperclass.getActualTypeArguments()[1];
    }

참조 링크에 있는 JPA 패턴을보다가 발견한 이 코드를 응용해서 사용하시면 되겠습니다.

이로써, 보다 깔끔한 GenericDao를 만들 수 있겠네요. 하나 덤으로 위 링크에 첨언을 하자면, 위 링크에서는 주키 타입도 Generic 타입으로 지정해서 일일히 지정받고 있는데, 저는 그것보다 Serializable을 사용하면 타입 인자를 하나 더 줄일 수 있는데다, 키 타입에 대해 별다른 제약도 없기 때문에 더 깔끔하지 않나 생각하빈다.

ps: 오랜만에 HibernateGenericDao를 TDD로 만들고 있는데 재밌네요. 별거 아니지만;; 만들면 공개해볼까 합니다.
top

Write a comment.


[EGIU] Unit 19, 20정리

모하니?/English : 2009. 9. 2. 17:29


Unit 19. Present Tenses for the futer (I am doing / I do)

A: 현재 진행형으로 미래를 표현하기

이미 결정했거나 그렇게 하려고 조정/약속/예정되어 있는 행위를 표현한다.
결정했다는 의미를 나타낼 땐, I am going to (do)를 사용해도 된다.
하지만, 조정/약속/예정의 뜻을 나타낼 때는 I am doing이 더 자연스럽다.

외울문장
- Alex is getting married next month.
- I'm not working tomorrow.
- What time are you ariving?

B:현재형으로 미래 표현하기

시간이 정해져 있거나 공적으로 딱 짜여져 있는 경우에 사용한다.
하지만 사적인 경우에는 현재 진행형을 쓰는 것이 자연스럽다.

외울문장
- My train leaves at 11.30.
- The firm begins at 8.15.

틀린문제 0개.

Unit 20. (I'm) going to (do)

I am going to do ~: 무언가를 하려고 결정했고, 하려고 한다.
I am doing은 무언가가 예정되어 있는 것인 반면, I am going to do는 결정했다는 의미가 강하다.
둘의 차이가 미세하기 때문에 혼용하기도 한다.
미래에 어떤 일이 일어날 것이라는 표현으로 쓰기도 한다.
I was goting to ~: 그려려고 했었지만, 하지 않았다는 것을 표현할 때 사용한다.

외울문장
- What are you going to eat?
- Who are you going to invite?
- I'm not going to accept it.

틀린문제 0개.


top

Write a comment.


쓰리좝 시작인가...

모하니?/Thinking : 2009. 8. 31. 16:44


고등학생 수학 과외를 봐주기로 했습니다. 생업은 지금 다니는 회사에서 ERP(보다는 쉬워보이는)라고 할까나.. 암튼 제품을 보다 효율적으로 관리할 수 있는 시스템을 개발 및 유지보수를 하는 일이고, 두 번째 업은 번역인데 한 번 해보고 난 뒤 사기가 많이 떨어졌습니다. 이제는 세 번째 업인 과외를 시작하기로 했습니다.

과외는 세금도 안 떼고 시간당 페이도 괜찮기 때문에 적극적으로 하고 싶은데 개발과 관련된 분야가 아니라는 것이 좀 문제입니다. 고등학생 수학을 봐주기로 했는데 어쩌면 수학 공부를 해가면서 가르쳐야 할지도 모르겠습니다. 수학에서 손뗀지 10년이 다 되가는군요. 뭐.. 동생이 수학과를 나왔으니 모르는걸 물어볼 사람은 있어서 다행입니다.

예전에도 몇 번 과외를 해본적은 있지만, 제가 갈쳤던 학생들은 전부 공부를 하기 싫어했던 학생입니다. 잘하고 싶다는 생각도 없고, 숙제도 하기 싫어하고~ 지금 가르치려는 학생도 이미 전에 한 번 실험삼아(?) 갈쳐봤던 학생인데 공부에 맘이 없는 듯 하여 한 달만 하고 말았었습니다. 그런데 최근에 다시 연락이 왔네요. 애가 다시 공부를 하고 싶어한다고... 과연.. 공부가하고 싶은건지.. 상담 선생이 필요한 건지는 가봐야 알겠지만...

이번에도 공부에 맘이 없다면 금방 끝날 일인 듯 하네요.

흠.. 이왕 하는거 목동에 전단지 막 뿌리고 해볼까나...

"개발자로 키워드려요~ 이제 영어는 기본이다.
누구나 하지 못하는 코딩 조기 교육으로 특기자 전형을 노리세요~"

ㅋㅋㅋㅋ
top

  1. 머큐짱 2009.09.01 00:09 PERM. MOD/DEL REPLY

    백기선님~ 몸이 12개,, 한번더~! ㅋㅋ

    저도 투잡, 쓰리좝.. 뛰고 싶어요..ㅎ

    "영재 개발자 교육센터" 함께 추진해볼까요?ㅎㅎ

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.09.01 06:55 PERM MOD/DEL

    재밌을 것 같은데 말이죠..
    봄싹 청소년 개발자 교육센터~ 캬..

  2. Favicon of http://nije.pe.kr BlogIcon 김재진 2009.09.01 08:25 PERM. MOD/DEL REPLY

    얼! 쓰리좝!!

    전 요즘 투좝은 해볼까 하고 구상중이래요!!

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.01 08:49 신고 PERM MOD/DEL

    개발로 투좝은 넘 힘들지 않아?
    돈 모아서 닭집이라도 해야되나..

  3. Favicon of http://blog.naver.com/j81811 BlogIcon aStRe 2009.09.01 08:47 PERM. MOD/DEL REPLY

    1. 목동에 자리펴요!!!이번주 스윙엄써/

    2. 핸폰 놓고 갔답니다ㅠㅠ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.09.01 08:50 신고 PERM MOD/DEL

    엇.. 글쿤..

Write a comment.


9월에 할 일 정리

모하니?/Planning : 2009. 8. 31. 12:28


1. 봄싹 스터디 및 사이트 개발
- 몇일 전 오픈한 봄싹 사이트 유지 보수를 한 달 간 진행하고, 스터디를 본격적으로 시작할 계획입니다.
- 하이버네이트 스터디가 유력하며..
- 스프링 DM 스터디도 유력하고..
- 스프링 Roo 역시 유력합니다.

2. 하이버네이트 번역
- 너무 많이 미뤄뒀네요. 이제는 다시 열을 올려서 끝내야겠습니다.
- 다음달까지 맡은 부분 번역을 다 끝내는 것이 목표입니다.

3. 회사일
- 당분간 인천 남동공단으로 출퇴근 해야 할지도 모르겠습니다.
- 이럴 땐 운전도 못하고 차도 없는게 아쉽지만, 걍 전철하고 버스 타고 가다보면 어떻게든 다닐 수 있겠죠.

4. 스윙댄스 졸업공연 준비
- 얼마있음 졸업 공연이라는데 안무와 음악을 전부 와이프한테 위임할 생각입니다.
- 신경쓸 겨를이 없는데.. 모여서 다른 커플들과 모여서 준비를 해야 되네요.
- 아마도 다다음주가 마지막일 듯.

5. 보라카이 여행 준비
- 엊그제 제주도에 다녀왔는데 이번에는 한 달 뒤에 보라카이를 갑니다.
- 가지고갈 짐, 비행기 호텔 예약 확인, 현지 물가 확인, 환전 등
- 오늘밤에 대충 끝내야겠네요.

보라카이는 3시간만 빡쎄게 조사하면 끝날테고..
스윙댄스는 집에서 하루 한 시간씩만 하고..
하이버네이트 번역은 출퇴근 시간에 하던 집에서 스윙 연습 끝내고 하던 꾸준히 해야될테고..
회사일은 인천으로 출퇴근하면서 피곤해지고 깨지고 들들 볶이면 되는거고..
봄싹 개발은 이제 주말에만 해야겠군요.
이러면서 평소에도 꾸준히 영어와 스프링 공부도 하고 피아노도 쳐야하는.. 9월 이로군요.

'모하니? > Planning' 카테고리의 다른 글

봄싹을 알리러 갑니다.  (6) 2009.11.24
[Atlassian] 이직 계획  (2) 2009.11.02
[ToDo] 20091016  (0) 2009.10.16
[ToDo] 오늘 할 일 - 할일(예상 소요 시간)(실제 소요 시간)  (4) 2009.10.15
2009년 마무리로 할 일  (4) 2009.10.08
9월에 할 일 정리  (10) 2009.08.31
공부할 것 정리  (6) 2009.03.16
요즘 내 우선순위  (2) 2009.01.22
봄싹 3기 TDD 스터디 장소 시간 확정 됐습니다.  (2) 2008.12.30
봄싹 3기 TDD 스터디 계획  (4) 2008.12.29
이번 주 할 일  (0) 2008.12.23
top

  1. Favicon of http://blog.naver.com/cain007 BlogIcon 자화자찬 2009.08.31 13:46 PERM. MOD/DEL REPLY

    와... 벌써 결혼도 하셨구나...

    사진보고 전 대학생인지 알았어여...

    스펙보고 범상치 않으시다 햇는데

    회사도 다니시고...

    학생인지 알았어여...진심..

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.31 14:03 신고 PERM MOD/DEL

    헉.. 저한텐 스펙이랄께 없는걸요.
    동안으로 봐주셔서 감사합니다.ㅋ

  2. Favicon of http://blog.naver.com/j81811 BlogIcon 아쓰 2009.08.31 14:49 PERM. MOD/DEL REPLY

    9월엔 할일이 태산이로군요..
    스윙이랑. 보라카이는 내가 알아서 하고 마지막에 검토만 하세요.
    그럼 일이 좀 덜어 질 테니깐은~!

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.31 15:02 신고 PERM MOD/DEL

    역시 멋진 와이 프로군!!
    스윙은 그럼 자기가 리더 하는거야?ㅋ

  3. Favicon of http://blog.naver.com/j81811 BlogIcon 아쓰 2009.08.31 15:06 PERM. MOD/DEL REPLY

    내가 안무 다 짜고 음악 다 믹싱하고 자기 가르쳐서 리드하게 하고
    우리 빡세게 연습해서 토욜은 다 같이 1~2시간 정도 하도록 할라고.
    그리고 적은 인원보다는 많을 수록 좋다는데...
    8명 정도 하면 뭘 해도 멋지데.. 적은 인원이면 skill이 필요하고. 많은 인원은 그냥 웅장함?
    그래서 어찌 할까 생각중이야...

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.31 15:33 신고 PERM MOD/DEL

    양보다 질이야. 스킬로 나가자.

  4. Favicon of http://blog.naver.com/j81811 BlogIcon 아쓰 2009.08.31 15:52 PERM. MOD/DEL REPLY

    그러시죠~!
    케이통역사가 "에어" 알려줬어. 작히가 원하는 180도 도는거.
    이따가 같이 동영상봐~! 완전 멋지다. 찰스톤이랑 에어랑 몇 개만 응용해서 하면 되고.
    안무 거의 짰어. 이따가 음악에 맞춰 순서만 바꾸면 될꺼 같고.
    아직 안 배운 것 완전 멋진거 몇 개도 있어. 굿굿~!

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.31 16:04 신고 PERM MOD/DEL

    ㅇㅇ좋구만.
    이따봐요/

  5. 머큐짱 2009.08.31 18:02 PERM. MOD/DEL REPLY

    쭈욱~ 지켜 봤는데요..

    기선님은 몸이 12개인게 분명해..ㅋㅋ

    부러워용~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.31 20:23 신고 PERM MOD/DEL

    뭔가 하나에 집중을 잘 못해서 그런가봐요.
    차라리 몇 개 줄이고 하나에 집중하는게 나을것 같다는 생각도 자주 합니다. ㅠ.ㅠ

Write a comment.


[봄싹 오픈] springsprout.org

모하니?/Coding : 2009. 8. 27. 22:08


www.springsprout.org

드디어 봄싹 스터디 새로운 시즌을 시작합니다.


스터디에 가입 하지 않으셔도 어느 정도 구경은 하실 수 있습니다. 어느 정도만~
아직 미흡한 부분이 많지만, 분명히 점차 개선될 겁니다.

1차 오픈을 할 수 있었던 건 전부 봄싹 개발에 참여해주신 열 분의 개발자들 덕분입니다.

이것 저것 프로젝트 하느랴 바빴을텐데 가장 열정적으로 참여해준 성윤이.
스터디쪽 미흡하다고 한 마디 했더니 몇 일만에 모든 기능을 다 만들어버린 재진이.
깔끔한 개인화면 만들어준 막내.
다소 늦게 개발에 참여했지만, 그래도 저와 함께 회원 모듈을 당당하고 파일 업로드를 담당하고 계신 종봉이형
Ajax, 시큐리티, 제이쿼리, 맵 오픈 API 등 두루 두루 담당하고 개발해주신 정우형.
오프라인에서는 못 봤지만, 어느새 온라인에서 혼자 세미나를 전부 만들어준 명수형.
오프라인에도 자주 참석해주신 소내기형. 역시 혼자 위키를 전부 만들어주셨습니다. 아주 든든해요. 캬~
개발에는 직접 참여해주시지 않았지만, 메일링 통해서 여러 조언을 해주신 성철형님
그리고 마지막으로 약속을 지켜낸 저까지.

현재는 이렇게 10명이 만들고 가꾸고 있습니다. 앞으로 더 여러 개발자들과 함께 가꿔나가고 싶네요.
top

  1. Favicon of http://helols.pe.kr BlogIcon 성윤 2009.08.27 22:26 PERM. MOD/DEL REPLY

    찡해요;;ㅋㅋ
    형도 수고 해썽요 ... ㅎㅎ

    앞으로 해나가야 할게 더 많아 보여요..ㅋ
    앞으로 스터디 더 열심히 해서 .. 튼튼한 봄싹 만듭시다 !! ㅎㅎ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.27 23:14 신고 PERM MOD/DEL

    응 완전 수고했어!!
    계속 가꿔보자.

  2. 안녕하세요` 2009.08.27 22:37 PERM. MOD/DEL REPLY

    봄싹 스터디 관심있게 보고있습니다 ^^

    살짝 둘러보긴 했는데 ~

    위에 링크가 살짝 잘못 되어있는듯합니다

    처음에 링크 눌러서 살짝 놀란..ㅎ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.27 23:14 신고 PERM MOD/DEL

    ㅋㅋ감사합니다~

  3. Favicon of http://toby.epril.com BlogIcon 2009.08.27 22:48 PERM. MOD/DEL REPLY

    링크가 틀렸자나. 글씨만 크게 하면 머해~

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.27 23:13 신고 PERM MOD/DEL

    ㅋㅋㅋ 이제 발견했네요.

  4. 머큐짱 2009.08.28 00:26 PERM. MOD/DEL REPLY

    짝짝짝~~

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.28 09:06 PERM MOD/DEL

    짝짝짝짝짝!!

  5. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.08.28 00:54 PERM. MOD/DEL REPLY

    축하드립니다!
    경험을 통해 얻은 지식을 공유한다는 말씀이죠? 정말 괜찮네요. :)

    그나저나 사이트 대문에 보이는 고기 사진을 보니
    고기 덕후 모임 같은 느낌이...
    거기다가 아이콘까지 보니 상추쌈을 싸야할것 같은 기분이...@_@;
    절대 한밤중에 고기 사진 봐서 먹고 싶어서 그러는거 맞습니다.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.28 09:06 PERM MOD/DEL

    감사합니다.

    첨으로 다녀온 MT라 별거 없었는데도(고기만 있었어요,)
    즐거웠어요.ㅎㅎ

  6. Favicon of http://yunsunghan.tistory.com BlogIcon Max 2009.08.28 09:04 PERM. MOD/DEL REPLY

    축하 드립니다. ^^*.
    헌데, RSS 등록하고 싶은데, 주소가 어떻게 되죠?

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.28 09:04 PERM MOD/DEL

    아직 RSS는 안 만들었어요.ㅋㅋ
    후딱 만들어야겠네요.

  7. 궁금이 2009.08.28 10:04 PERM. MOD/DEL REPLY

    whiteship님 궁금한게 있는데 질문 하나만 드려도 될런지요
    Security로 권한부분에서 ACL로 하셨는지 SecurityContext 조작으로 하셨는지 ^^;?
    (저도 지금 이부분에 대해서 고민중이라...)

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.28 10:53 PERM MOD/DEL

    ACL은 (제가 잘 몰라서) 사용하지 않았구요. 기본적인 URL 패턴 보안과 애노테이션 기반 메서드 보안을 사용했습니다.

  8. 양완수 2009.08.28 11:27 PERM. MOD/DEL REPLY

    축하드려요 ^^
    가입했습니다.
    시원하고 깔끔하네요 ~~!!

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.28 11:40 신고 PERM MOD/DEL

    감사합니다 ^^

  9. Favicon of http://okjsp.tistory.com BlogIcon kenu 2009.08.28 12:46 PERM. MOD/DEL REPLY

    www.springsrout.org -> www.springsprout.org
    축하해. ^^

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.28 17:00 신고 PERM MOD/DEL

    에구머니나. ㅎㅎ

    감사합니다~

  10. 이진서 2009.08.28 17:24 PERM. MOD/DEL REPLY

    축하드립니다. ^^*

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.28 20:05 PERM MOD/DEL

    감사합니다. ^^

Write a comment.


[봄싹] D-day 오후 10시에 오픈하겠습니다.

모하니?/Coding : 2009. 8. 27. 15:58


현재 피튀기게 개발 중입니다. 몸이 10개였으면 좋겠어요. 안 믿으실까봐.. 증거자료 재출합니다.


보세요.. 불과 1시간전에 올린 글인데.. 댓글이 장난 아니죠. @_@ 결국은 명수형이 태그파일 만드는 걸로 결론이 났군요. 캬...

1차로 css로 간단하게 적용하고
2차로 스프링이 제공하는 HTMLUtils를 써보고
3차로 그것을 태그파일로 다듬고
4차는 다시 1~3차를 엎어버리고, 에디터를 적용하는 것..

이 중에서 3차까지는 한 다음 오픈을 할 것 같습니다. 따끈따근한 봄싹 개발 현장이었습니다. ㅎㅎ

불량사원으로 찍히실까봐.. 닉넴은 대충 모자이크 처리했습니다.
봄싹의 에이스 개발자들이 불량 사원으로 찍히는 이것이 바로 "봄싹 딜레마"

top

  1. Favicon of http://helols.pe.kr BlogIcon 성윤 2009.08.27 16:07 PERM. MOD/DEL REPLY

    디벨로퍼 페이지는 어쩌시려구요;;ㅋㅋ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.27 16:36 신고 PERM MOD/DEL

    사람들이 모를꺼야.. 천천히 수정하지 뭐 ㅋㅋㅋ

  2. Favicon of http://blog.naver.com/j81811 BlogIcon 아쓰 2009.08.27 17:51 PERM. MOD/DEL REPLY

    오~ 드뎌 오픈이로군... ㅋㅋㅋ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.27 18:17 신고 PERM MOD/DEL

    ㅇㅇ오.. 드뎌 퇴근이로군.

Write a comment.


[봄싹] 시즌 2 오픈 D-1

모하니?/Coding : 2009. 8. 26. 07:18


내일 오픈 합니다. 이번 주 월요일부터 예비군 동미참훈련? 때문에 월.화,수를 교장으로 출퇴근하고 있습니다. 막바지에 소중한 시간을 뺏겨서 아쉽긴하지만, 다른 봄싹 에이스분들께서 많이 신경써 주셔서 무사히 원했던 일정에 맞춰서 오픈할 수 있게 됐습니다.

봄싹 프로젝트와 관련해서는 하고 싶은 이야기들이 상당히 많은데, 그 중 몇 가지 주제들만 뽑아 보면 다음과 같습니다.

- 각종 프레임워크 및 개발환경 도입 성공 사례(하이버네이트, 시큐리티 3.0, 메이븐, CI 툴, 테스트 등)
- 기트 도입 실패 사례(이전에 공유한바 있습니다.)
- 봄싹 개발 프로세스
- 자율적이고 자연스러웠던 작업 세분화
- 데드라인
- 메일링 리스트 활용

이 것들은 제가 느낀점들이고, 다른 봄싹 에이스 분들께서 느낀 주제들도 잘 정리해서 공유할 날이 있을 것 같습니다.

드디어.. 마음대로 주무를 수 있는 홈 페이지가 생겨서 정말 기쁩니다. 비록 몇 달간은 베타 버전으로 공개하겠지만, 차차 스터디에 필요한 기능들을 더 다듬고 추가하면서 꾸준히 발전할 겁니다. 봄싹 파이팅~!!
top

  1. Favicon of https://yangwansu.tistory.com BlogIcon 양완수 2009.08.26 14:44 신고 PERM. MOD/DEL REPLY

    제작 발표회를 한번 가져보시는 건 어떤지요?? 적극 참여 가능합니다. ^^

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.26 18:54 PERM MOD/DEL

    네 올해가 가기전에 세미나를 할 생각입니다.

Write a comment.


[봄싹] 시즌2 다음 주 오픈 예정

모하니?/Coding : 2009. 8. 17. 11:08



날짜를 보세요. 이 많은 이메일이 대부분 토요일과 일요일 그리고 월요일에 토론 중인 메일 목록입니다. 캬... 멋지죠.

열심히 달리고 있는 봄싹 개발자는 현재 총 10명입니다.
기선, 재진, 성윤, 정우, 재일, 수진, 대웅, 종봉, 명수, 성철.
모두 정말 감사합니다.

다음주 주말 전에 1차 오픈 준비가 끝나면, 급하게라도 개발자 페이지를 추가하겠습니다.
일주일만 더 불량 사원으로 지내봅시다!! 봄싹 베스트 회원이 되실겁니다!! 파이팅!!!!

top

  1. Favicon of http://sonegy.egloos.com BlogIcon 소내기 2009.08.17 22:22 PERM. MOD/DEL REPLY

    이 사실을 회사에 알리지마~ ㅋㅋㅋ

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.17 23:58 PERM MOD/DEL

    ㅎㅎㅎㅎ

Write a comment.


[잡담] 예비군 4년차 훈련 시간

모하니?/그냥 놀아 : 2009. 8. 17. 09:58


6, 6, 24(8*3)

주소지를 바꿨더니 그 새 훈련 기간이 끝나버려서 안 받아도 되는 줄 알았건만.. 그게 아니더군요. 지난 번에 6시간 교육을 다녀왔으니 이제 남은 교육 시간은 30시간. 6시간 짜리 교육 하나와 3일간 8시간 교육을 받으러 출퇴근해야 되는 24시간 짜리 교육이 남았습니다.

오늘 저녁 6시부터 자정 12시까지 6시간 짜리 교육을 받으러 갑니다.
다음 주 월, 화, 수 3일간 오전 9시까지 안양박달교장 이라는 곳으로 오라고 합니다.

1년 중에 총 36시간. 일수로는 5일을 잡아먹는 훈련. 혹자는 이걸 휴식이라며 좋아도 하시지만 전 너무 싫어요. 시대가 어느땐데 파씨즘적인 동영상 시청에 산에 올라가서 의미없는 삽질이나 해데고.. @_@ 그럴바엔 하지 말자고요. 콜오브듀티 5로 시뮬레이션을 하자니까... 그럼 내가 40시간에 6일을 가도 흔쾌히 가겠다.

아휴 짜증나!!!! 더워죽겠는데 국방의 의무는 무슨!! 너나 가!!

http://loved.pe.kr/entry/hannara-minjoo
top

  1. Favicon of http://deuxksy.tistory.com BlogIcon 김석영 2009.08.17 23:40 PERM. MOD/DEL REPLY

    ㅋㅋㅋㅋ 저는 올해 6년차 후반기 8시간만 남았습니다. 더운되 고생하셨겠네요 ㅋㅋㅋ

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.17 23:57 PERM MOD/DEL

    부럽!!

  2. Favicon of http://blog.naver.com/j81811 BlogIcon 아쓰 2009.08.18 10:55 PERM. MOD/DEL REPLY

    그래도 해야지.. 안하면 벌금 낸다..-_-;;국적을 바꿔. 프랑스는 의무 하루야. 평생에 하루.

    Favicon of http://whiteship.me BlogIcon 기선 2009.08.18 11:52 PERM MOD/DEL

    평생에 하루라..괜찮군

  3. Favicon of http://blog.naver.com/j81811 BlogIcon 아쓰 2009.08.18 13:25 PERM. MOD/DEL REPLY

    한국은 2년 의무라고 했떠니 c'est un salop..putain;;; 이라는 반응이..ㅋㅋ
    고작 하루 가는 것도 울면서 가드라..;;-_-+

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.18 14:08 신고 PERM MOD/DEL

    2년은 무슨 예비군 6년차까지 치면 8년이지.
    내년엔 5년차니까 6 8 6 다녀와야 돼

  4. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.08.20 21:02 PERM. MOD/DEL REPLY

    그래도 불러줄때가 좋은겁니다.
    저는 이제 불러주지도 않... 어흑... ㅠ_ㅠ

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.21 00:06 PERM MOD/DEL

    호주에 계신 분까지 불러들여서 훈련시키면 비행기 표값을 줄지도.. @_@

  5. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.08.25 01:15 PERM. MOD/DEL REPLY

    오! 비행기표값이라...만약 그렇다면...
    역시 불러줄때가 좋은거 같습니다. :D

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2009.08.26 18:55 PERM MOD/DEL

    드디어 오늘부로 4년차 훈련 끝났습니다.
    ㅎㅎ 내년부턴 5년차~

Write a comment.


[테스트] 커스텀 MimeMessageHelper 테스트하기

모하니?/Coding : 2009. 8. 14. 14:07


MimeMessage를 사용해서 실제로 메일을 보내보고, 메일이 깨지지는 않는지 확인해보고 싶어서 다음과 같은 테스트를 작성했습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testContext.xml")
public class SignupConfirmMimeMessageHelperTest {

    @Autowired
    JavaMailSender mailSender;

    @Test
    public void sendInteface() {
        MimeMessage mimeMessage = mailSender.createMimeMessage();
        Member member = new Member();
        member.setEmail("whiteship2000@gmail.com");
        assertNotNull(mimeMessage);
        SignupConfirmMimeMessageHelper helper = new SignupConfirmMimeMessageHelper(mimeMessage);
        helper.makeMessage(member);
        mailSender.send(mimeMessage);
    }

}

테스트를 만들면서 JavaMailSender와 MimeMessage, SignupConfirmMimeMessageHelper 클래스를 어떻게 사용할지 고민을 했죠. 생성자에 member도 같이 줘봤다가.. 뺏다가.. 했습니다. 결국은 빼냈습니다. 중요했던 건 SignupConfirmMimeMessageHelper 클래스의 생성 방법과 사용방법 이었습니다.

저런식으로 실제 메일을 보내 본 뒤.. 그대로 두면.. 테스트가 돌 때 마다 저한테 메일을 보내줄 겁니다. 상당히 귀찮은 테스트입니다. 그래서 생각을 했습니다. 안 되겠다. 어차피 메일 보내는 것도 확인했고.. 인코딩도 확인했고.. 내가 이 테스트에서 정하고자 했던 건 SignupConfirmMimeMessageHelper 클래스의 생성자 구조랑 사용법이니깐... 단위테스트로 고치자~

@RunWith(MockitoJUnitRunner.class)
public class SignupConfirmMimeMessageHelperTest {

    @Mock JavaMailSender mockSender;
    @Mock MimeMessage mockMessage;

    @Test
    public void sendInteface() {
        assertNotNull(mockSender);
        assertNotNull(mockMessage);
        when(mockSender.createMimeMessage()).thenReturn(mockMessage);
       
        MimeMessage mimeMessage = mockSender.createMimeMessage();
        Member member = new Member();
        member.setEmail("whiteship2000@gmail.com");
        SignupConfirmMimeMessageHelper helper =
            new SignupConfirmMimeMessageHelper(mimeMessage);
        helper.makeMessage(member);
        mockSender.send(mimeMessage);
    }

}

그래서 이렇게 고쳤습니다. 고치고 나니까... 이런 생각이 드네요.


맨 마지막 줄만 지워버릴껄 그랬나.... 허허헐...
top

Write a comment.


[스프링 이메일] MimeMessageHelper 초간단히 사용하기

모하니?/Coding : 2009. 8. 14. 12:09


    private MimeMessage makeTestMimeMessage() throws MessagingException,
            AddressException {
        MimeMessage message = javaMailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message);
        helper.setTo("whiteship2000@gmail.com");
        helper.setFrom("s2cmailer@gmail.com");
        helper.setSubject("This is the Subject Line!");
        helper.setText("<h1>This is actual message</h1><a href=\"ads\">hi</a>", true);
        return message;
    }

    private MimeMessage makeTestConfirmMimeMessage() throws MessagingException,
            AddressException {
        MimeMessage message = javaMailSender.createMimeMessage();
        message.setFrom(new InternetAddress("s2cmailer@gmail.com"));
        message.addRecipient(Message.RecipientType.TO,
                                 new InternetAddress("whiteship2000@gmail.com"));
        message.setSubject("This is the Subject Line!");
        message.setContent("<h1>This is actual message</h1><a href=\"ads\">hi</a>",
                           "text/html" );
        return message;
    }

둘 중에 어떤 코드를 쓰느냐는 코딩하는 사람 맘이겠지만, 위에 있는 것이 훨씬 깔끔해 보이지 않나요. Helper를 이용해서 좀 더 직관적인 메서드 이름과 편리한 인터페이스로 MimeMessage를 작성할 수 있습니다.

애용하세요~
top

Write a comment.


허경영의 콜미

모하니?/Watching : 2009. 8. 13. 11:24




가수로 데뷔하신다는데.. 가요 프로에서 보면 정말 재밌을 것 같네요.
구라때문에 감방도 다녀오셨는데 오히려 업그레이드(?)되서 오신듯..
'무중력춤'과 '오링춤'도 너무 기대되요!! +_+

ps: 왠지 벨소리로 대박 날 듯 함...

top

TAG 허경영

Write a comment.


제주도 또 가겠구나~

모하니?/그냥 놀아 : 2009. 8. 11. 22:01



신혼여행으로 4박5일을 다녀왔지만, 너무 볼거리가 많아서 아쉬웠는데 다시 가게 되서 신나네요. 캬캬캬.
3만원에 1박 2일! 와이프도 신났네요. 크하하. 여보 내가 이정도야! 음하하하하
top

  1. Favicon of http://j-man.tistory.com BlogIcon j.man 2009.08.11 22:23 PERM. MOD/DEL REPLY

    와,, 정말 부럽습니다.

    Favicon of http://whiteship.me BlogIcon 기선 2009.08.12 09:35 PERM MOD/DEL

    ㅎㅎ감사합니다.

  2. Favicon of http://toby.epril.com BlogIcon 2009.08.11 22:33 PERM. MOD/DEL REPLY

    아 배아파.

    Favicon of http://whiteship.me BlogIcon 기선 2009.08.12 09:35 PERM MOD/DEL

    제주도보다 좋은 호주에 계시면서.. 무슨~

  3. Favicon of http://helols.pe.kr BlogIcon 성윤 2009.08.12 00:36 PERM. MOD/DEL REPLY

    ㅊㅋㅊㅋㅊㅋ ㅋㅋ

    Favicon of http://whiteship.me BlogIcon 기선 2009.08.12 09:35 PERM MOD/DEL

    ㄱㅅㄱㅅㄱㅅ
    그나저나 봄싹 오픈을 제주도에서 하겠구나~

  4. Favicon of http://blog.naver.com/j81811 BlogIcon 아쓰 2009.08.12 09:24 PERM. MOD/DEL REPLY

    능력자 남편 덕분에 항상 호강하고 행복한걸~!
    완전 작히 짱이얌! 이뻐이뻐이뻐!! 짱 이뻐!!!

    더미: 근데 쵸콤 눈치는 보일듯;; ㅋㅋㅋ

    Favicon of http://whiteship.me BlogIcon 기선 2009.08.12 09:35 PERM MOD/DEL

    어쩔 수 없어. 부부는 일심동체야.
    그게 세상의 이치니까~

  5. Favicon of http://blog.lckymn.com BlogIcon Kevin 2009.08.12 12:09 PERM. MOD/DEL REPLY

    제주도 가신다니... 제주도 좋으시군요. :) (아, 이건 재주구나...ㅡ_ㅡ; )

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2009.08.12 12:35 신고 PERM MOD/DEL

    오호.. 위트가 넘치시는데요~ 캬캬.

Write a comment.


[EGIU] Unit 13, 14 정리

모하니?/English : 2009. 8. 11. 18:24


Unit 13. Present perfect and past 1 (I have done and I did)

현재완료
- 현재와 관련이 있다.
- 최근에 새로운 일이 벌어졌을 때 사용한다.

과거
- 과거에 있었던 일이다.
- 새롭거나 최근의 일이 아닐 때 사용한다.

외울 문장
- He has lost his key (지금도 못 찾고 있다.)
- He lost hist key (과거에 잃어버린적이 있다. 지금은 찾았을 수도 있고 못 찾았을 수 도 있다.)
- I've reqaired the TV
- Who invented the telephone??

틀린 문제 2

A: Are you still reading the paper?
B: No __________ (finish) with it. You can have it.
=> I have finished with it.

이미 예전에 읽었다고 하는 걸까봐 finished를 썼지만 질문에서 still로 물어보고 있으니 최근 상황을 얘기하는 것으로 짐작하고 have + p.p를 써주는게 좋을 듯..

When were you born?
수동태 주의 할 것.

Unit 14. Present perfect and past 2 (I have done and I did)

과거
- 끝난 시간(yesterday, ten minutes ago, in 1999)을 이야기 할 떄는 현재완료를 쓰지 않는다.
- When 이나 What time 으로 물어볼 땐 과거형을 쓴다.

현재완료
- today/this week/since ~ 를 사용할 때 현재완료를 사용한다.

외울 문장
- When did your friend arrive?
- I got home late last night.
- Have you seen Tim recently?
- Dod you see Tim on Sunday?

틀린 문제 3

When _______ published?
=> When was this book published?
When으로 물어봤기 때문에 과거형이 와야 함.
수동태 주의 할 것.

A: Where do you live? B: In Boston.
A: How long ________(you/live) there? B: Five years.
A: Where ________(you/live) before that? B: In Chicago.
A: And how long __________(you/live) in Chicago? B: Two years.
=> 첫 번째 것은 현재 완료. 다음 두 개는 모두 과거 형을 써야함.
현재


'모하니? > English' 카테고리의 다른 글

[BBC News] Toyota recall reaches Eupore  (2) 2010.02.22
[BBC News] Baijing hit by record snowfall  (4) 2010.02.19
[BBC News] Naples pizza protected by EU  (5) 2010.02.18
[BBC News] Ukraine and Russia argue about spies  (2) 2010.02.17
[EGIU] Unit 19, 20정리  (0) 2009.09.02
[EGIU] Unit 13, 14 정리  (0) 2009.08.11
[EGIU] 20090807 Unit 9, 10 정리  (0) 2009.08.07
20090801 Unit 7, 8 정리  (2) 2009.08.01
090731 Unit 5, 6 정리  (6) 2009.07.31
090730 Unit 3, 4 정리  (0) 2009.07.30
090729 Unit 1, 2 정리  (6) 2009.07.29
top

Write a comment.




: 1 : ··· : 4 : 5 : 6 : 7 : 8 : 9 : 10 : ··· : 32 :