무료문자발송 프로그램 MurMur v0.3

http://kr.code4mac.net/

맥용 프로그램인데, 네이트온 무료문자창의 무료 및 문자쿠폰 건수까지 사용해서 발송 가능합니다.
네이트 캐쉬도 사용가능하도록 기능 추가하는 것 어렵지 않아 보이는군요.

맥이라서 그런지 디자인 마음에 드네요.
이런 서드파티 프로그램들은 막아야할지 말아야할지 고민중입니다.


by 선인장 | 2009/06/01 10:31 | 네이트온 | 트랙백 | 덧글(1)

미투북마클릿 - 새창(새탭)으로 띄우기 버전

웹서핑 중에 괜찮은 것들 미투데이에 스크랩하는데, 미투북마클릿이 편리하더군요.

그런데 미투북마클릿이 새창/새탭으로 뜨면 편리하겠다는 생각이 들어, 조금 수정해보았습니다.

미투북마클릿과 동일한 방식으로, 북마크하시면 됩니다.

javascript:(function(){var%20d=document;var%20w=window;var%20me=function(el){var%20o=d.createElement(el);if%20(typeof%20o!='object'){o=d.standardCreateElement(el);}return%20o;};var%20gst=function(){var%20t%20=%20'';if%20(w.getSelection){t%20=%20w.getSelection();}else%20if%20(d.getSelection)%20{t%20=%20d.getSelection();}else%20if%20(d.selection){t%20=%20d.selection.createRange().text;}return%20t;};var%20title=d.title;if(gst()!='')title=gst();var%20me='\"'+title+'\":'+location.href;w.open('http://me2day.net/posts/new?new_post[body]='+encodeURIComponent(me));})()

by 선인장 | 2009/04/07 10:52 | 프로그래밍 | 트랙백(2) | 덧글(2)

한국에서 웹표준/크로스브라우징 지키기

웹표준에 대한 다분히 감정적인 논란이 진행되는 것을 보고, 댓글을 달려다가 너무 길어지길래 트랙백하기로 하였습니다. 원문: http://noneway.tistory.com/429

논란은 간단합니다. 작성자가 크로스브라우징을 지키지 않는 한국 사이트들을 비판하는 포스팅을 올렸고, 그에 대해 몇몇 개발자가 "현실을 모르는 탁상공론"이라는 논지의 댓글을 단 것입니다. 원포스트 작성자가 그들을 犬발자라며 다시 포스팅한 것이구요.(이 블로그 전체적인 문체가 예의를 지키며 부드럽게 쓰는 방식이 아니니, 犬발자, 단세포들, 등신짓, 궤변 등등의 단어에 괜히 집착하지 말기를 바랍니다.)

웹표준/크로스브라우징은 현실적으로 가능하다

'실천가'님의 댓글에 보면 "포털 메인 화면 같은 거 딱 한 페이지만 코딩해봐라"라는 말이 있던데, 제 경우엔 포털메인은 아니더라도 주요 서비스 중 하나를 전부 개발/운영 중이니 말할만한 자격을 충분히 갖춘 거죠? 웹to폰 SMS의 90%이상은 저희 시스템 통해서 나가지 않을까 합니다. 기획의도자체가 PC Applications 만큼의 기능성이라서 javascript를 얼마나 사용했을지 상상이 가시죠? 따라서 '지나가다', '실천가', '병신' 님의 "현실을 모른다"는 비난은 좀 무리가 있습니다. 메인페이지 개발자를 포함한 저희 회사 개발자들은 그일을 벌써 수 년간 해오고 있으니까요. 웹표준/크로스브라우징을 구현하는 것은 충분한 시스템이 갖춰져 있다면 분명히 "현실적으로도 가능"한 일입니다.

웹표준/크로스브라우징 준수는 원칙적으로 불가능

앞 문단과 모순되는 듯 보이지만, 그럼에도 불구하고 저에겐 犬발자라고 불리는 분들의 댓글이 단순한 궤변이나 변명으로 느껴지지는 않습니다. 현실적으로 어려움이 많고, 때로는 그 해결이 개발자의 영역 밖에 있는 경우도 있으니까요. "원칙적"으로 모든 사이트를 웹표준에 맞추고 크로스브라우징 가능하도록 개발하는 것이 가능하느냐라는 질문을 받는다면, 저는 "불가능하다"라고 대답하겠습니다

게다가 웹표준과 크로스브라우징은 전혀 별개의 개념입니다. 웹표준에만 맞게 작성한다고 모든 브라우저에서 잘 동작한다고 보장할 수 없고, 그 반대의 경우도 존재합니다. 만일 웹표준/크로스브라우징을 "웹표준에 맞게만 작성하면 크로스브라우징은 자동으로 보증된다"라고 이해하고 있다면 이것은 명백히 틀린 것입니다. (자세한 내용은 제일 아래부분 '덧붙여'에 설명해두었습니다)

웹표준은 말그대로 최소한의 표준일뿐이고, 표준화되지 않은 부분들에 대해서는 브라우저별로 알아서 구현되습니다. 이것은 웹표준 뿐 아니라 모든 기술스펙에 보편적인 사항인데, 웹표준스펙의 경우에는 특히 표준화가 더 불충분한 느낌입니다. 게다가 아직 working draft 상태죠?

게다가 웹표준과 크로스브라우징을 동시에 이루는 것은 불가능합니다. 모든 브라우저에서 동일하게 동작하기 위해 HTML 페이지의 웹표준을 희생하는 경우도 많이 있습니다. 예컨대, javascript 의 event 부분은 브라우저별로 차이가 큽니다. 이벤트 처리 코드들에서는 브라우저별로 분기하어 별도로 코딩하는 것이 필수적입니다. 내가 작성하는 코드가 다른 브라우저에서 동작할지 안할지는 해당 브라우저를 모두 테스트하기 전에는 전혀 알 수 없는 일입니다. 표준화가 잘 진행된 DOM 객체들 경우에도 모든 브라우저에서 동일하지 않은 예는 저 또한 많이 겪었습니다. 또는, 성능향상을 위해 javascript를  body 안에 넣는 비표준적인 일은 외국사이트들을 포함한 거의 모든 포털페이지들에서 자행(?)하고 있는 일일겁니다. 이것은 웹표준에는 맞지않지만 크로스브라우징이긴 하죠.

개발자의 영역을 넘어서는 일이다

크로스브라우징/웹표준을 고려한 개발은 개발자 혼자 마음먹는다고 가능한 부분이 아닙니다. 기획팀에서 작성한 UI 를 구현하려면 어쩔 수 없이 웹표준을 어기게 되는 경우가 있습니다. 일례로 저는 이번 개편때에도 iframe 을 제거하지 못했네요.

표준을 지키려면 기획팀/디자인팀 등과도 그 내용이 공유되어야하는데, 웹표준/크로스브라우징 자체가 기술적인 내용이라서 이들을 교육시키는 것은 개발자 교육보다 더 어렵습니다. 어느 정도 시스템이 갖춰져있다는 저희도 아직은 개발중에 기획서 수정을 요청하는 경우가 많이 있고, 일부 기능을 위해서는 표준을 희생하기도 합니다. 사정이 이러니 웹표준을 어기고 크로스브라우징이 안되는 사이트 개발자를 무턱대고 犬발자라고 부르며 비난하는 것은 좀 억울합니다. 우리 기획팀/디자인팀과 일정을 재촉하는 경영진을 함께 비난하시던지 ^^;

영세 Web Agency에겐 벅찬 일이다

개발영역에서만 보더라도 기존 코딩방식에 익숙한 개발자가 웹표준을 익히고 크로스브라우징을 고려하는 일이 말만큼 쉽지는 않습니다. 저희회사는 HTML코딩을 담당하는 팀에서 자바스크립트 코딩까지 99% 완료한 상태로 전달해줍니다. 저는 JSP 코드만 추가하는데, CSS관련 문제는 해당 팀에 문의하여 즉각적으로 답변 및 수정사항을 전달받습니다. 이렇게 일하면서도 처음 웹표준을 익히는데 몇 달은 걸리더군요. 전담팀의 도움 없이 웹표준을 익힌다는 것은 상상이 안갑니다.

게다가 단순히 크로스브라우징도 아니고 웹표준에 맞춘다는 것은 HTML에 대한 컨셉을 바꾸는 것이기 때문에 더욱 어려운 일입니다. 웹표준 관련 제대로된 책은 있나요? 웹표준 관련해서 찾아보고 물어볼 수 있는 블로그나 커뮤니티는 얼마나 될까요? 제게는 마치 윈도우만 써보던 개발자에게 "이제부터 PC포맷하고 리눅스깔아서 써라"라는 말정도로 들리네요.(책도 없이, man페이지 있으니 알아서 써라 정도?)  기존처럼 테이블들로 대충대충 꾸미다가, 구문맞춰서 HTML코딩하고 CSS로 모양 바꾸고 그러는 작업은, HTML에 대한 컨셉을 바꾸는 것이기 때문에 전혀 간단하지가 않습니다.

웹표준이라는게 영세한 Web Agency들의 능력으로는 개발자교육조차 어려워보입니다. 교육시켜줄 인력조차 없을테니까요. 그정도 훌륭한 코더라면 이미 큰회사에 스카웃되었을껄요. 사회적인 지원이 전무한 상황에서 '게으른 犬발자'라고만 비난하는 것은 지나칩니다. 저희처럼 전사적으로 웹표준관련 공유와 지원이 잘 되어있는 회사에서도 아직 한숨만 나오게 하는 개발자분들 많습니다. 하물며 영세업체들은 ㅡㅡ.

K리그에는 관심도 없으면서 한국축구가 월드컵 우승 못한다고 선수들의 정신력을 비난할 수는 없습니다. 제 생각에 웹표준/크로스브라우징은 IT업계전체의 의지가 필요한 이슈입니다. 그러나 30억으로 닌텐도DS를 만들어야하는 한국 사회는 당연히 그렇지 못합니다. 올봄부터인가 웹접근성관련 법안이 발효되어 표준을 제대로 지키지 못한 사이트를 소비자가 소송하는 것이 가능하다던데, 언제나처럼 위에 계신 분들은 막상 업체를 어떻게 지원할지에 대해서는 고민을 안하시고 계신 듯 하네요.

결론

  1. 꿈틀꿈틀님의 논지를 정확히 모르겠습니다. 웹표준을 지키라는 것인지 크로스브라우징 가능하도록 만들라는 것인지.
  2. 한국 개발자들이 웹표준을 지키지 않는 현실에 대한 책임을 100% 개발자에게 묻는 것은 억울한 일입니다. 개발자가 의지가 있더라도 충분한 인프라가 갖춰져있지 않기 때문입니다.
  3. 그럼에도 불구하고 웹개발자라면 관심을 좀 가져야합니다. 웹접근성/웹평등이란 온갖 어려움을 헤치고 어떻게든 나아가야할 바람직한 방향이니까요. HTML객체 접근할때 DOM방식만 사용하더라도 크로스브라우징의 90% 정도는 달성할꺼요.(not 웹표준) "document.all.forms[0].innerHTML"이런 건 좀 심하잖아요.
  4. 누가 웹표준/크로스브라우징 관련 블로그나 커뮤니티 좀 만들어 주세요.


덧붙여,WebStandard ≠ CrossBrowsing

웹표준/크로스브라우징이 전혀 다른 개념이고 서로 직접적인 관련이 없습니다.

  • 웹표준: W3C에서 작성 중인 표준안입니다. 아직 확정도 되지 않아서 working draft 상태로 알고 있고, 엄밀히 말해 권고안일 뿐이어서 이것을 따르지 않는다고 해도 형식적으로는 아무런 문제가 되지 않습니다. 아직 확정되지도 않고 계속해서 변하고 있는 표준안을 지키라는 요구때문에 브라우저 개발자들은 골치 꽤나 아플 겁니다.
  • 크로스브라우징: 말그대로 모든 브라우저에서 동일하게 보이고 동작하는 것을 의미합니다. 웹표준과는 전혀 별개죠. 예컨대 iframe 같은 것은 웹표준에 어긋나지만 PC상의 대부분의 브라우저에서 크로스브라우징됩니다.

사실 웹표준은 정확한 스펙 내용보다도 표준을 지정할때 지향하는 방향성이 더 중요할 것 같습니다. HTML의 내용과 Tag 가 적절한 의미를 가지고 조합되는 것이 그것인데, symantic 이라고 해야할까요? CSS가 로딩되지 않았을때 www.nate.com의 HTML 페이지를 보신적 있으신가요?  HTML은 의미를 가진 Document 가 되고, 그것을 화면에 보여주는 것은 CSS가 담당하도록 작성하는 것이 웹표준의 핵심이 아닐까 합니다. 이렇게 되면, CSS에 정의된 대로 제대로 표시하지 못하는 브라우저들의 경우에도 HTML 페이지를 읽는 것이 가능하게 되겠죠.

다른 브라우저 읽힌다라는 속성때문에 웹표준을 크로스브라우징과 많이들 혼동을 하지만,실제로 크로스브라우징은 전혀 다른 의미입니다. 앞서 말한 것처럼 어떤 브라우저에서 레이아웃이 다르게 보인다면, 일반적으로는 크로스브라우징이 안된다고 말을 합니다. 크로스브라우징은 모든 브라우저에서 완전히 동일하게 표시/작동될 때를 의미합니다. 반대로 iframe 같은 것은 크로스브라우징이지만 웹표준에는 어긋납니다.


꿈틀꿈틀님의 포스팅 몇 개를 보았는데, '웹평등'을 말하실때 웹표준이라고 말하면서 크로스브라우징을 의미하는게 아닌게 싶습니다. 가령 네이트/네이버사이트에서 광고배너나 검색창이 제 위치에 안보이는 것 자체가 웹표준을 어겼다고 말하는 것은 틀린 말입니다. 물론 웹평등/웹접근성에서 웹표준은 필수적인 개념이라는 것이 옳은 말이고, 관련 글들의 행간을 읽는다면 웹표준->웹평등성 으로 연결되는 사고의 흐름을 읽지 못할 바는 아닙니다. 하지만 글 자체에서 쓰일 때에는 웹표준과 크로스브라우징이 혼동되고 있는 것으로 보이네요. 웹페이지 작성시 symantic 을 지키라는 것인지, IE이외의 브라우저에서도 잘 돌아가도록 만들라는 것인지, 논지를 명확히 해주시면 더 읽기 좋을 것 같습니다.

by 선인장 | 2009/03/23 12:00 | 프로그래밍 | 트랙백(3) | 덧글(25)

이제 곧 없어질 엠파스 www.empas.com

오늘밤 드디어 사라집니다. ㅠ.ㅠ
안경쓴 토끼 아직도 생각나는데...
하지만 www.nate.com 은 더욱 더 이뻐지지요.

by 선인장 | 2009/02/27 16:58 | 네이트온 | 트랙백 | 덧글(2)

이제 곧 없어질 네이트 문자. sms.nate.com

오늘 밤 드디어 이쁜 디자인을 입고 다시 살아납니다.
이번엔 유난히도 디자인이 마음에 들어서 작업하는 내내 즐거웠습니다.

by 선인장 | 2009/02/27 16:56 | 네이트온 | 트랙백 | 덧글(0)

Strategy Patterm - examples

Strategy 패턴을 연습해보려고 직접 코드를 작성했습니다. 가위바위보 게임인데, 손을 내미는 전략을 Strategy 패턴을 사용해서 구현했습니다.

랜덤하게, 또는 순서대로 등등 전략에 따라 어떤 전략이 가장 승률이 높은지 계산해보기 위해 만들었습니다.

이 예제는 영진출판사의 "Design Pattern 입문"이라는 책의 예제를 모티브로 하여 만들었습니다.

 

소스는 http://realmoveprivatespace.googlecode.com/svn/trunk/designpattern/src/com/egloos/realmove/dp/strategy/ 에서 보실 수 있습니다. 동일한 경로에서 svn 다운로드도 가능합니다.

 

먼저,

com.egloos.realmove.dp.strategy.framework 패키지 아래의 세 파일이 기본이됩니다.

  • Hand : 가위,바위,보 를 나타내는 Enum 클래스
  • HandGameStrategy : Strategy 를 구현할 기본 interface. 손을 내미는 next() 와 승부결과를 받는 study() 메소드로 구성
  • Player : Strategy 를 사용하는 Context 역할

 

다음,

com.egloos.realmove.dp.strategy 패키지에 HandGameStrategy 를 구현하는 4가지 클래스가 있습니다.

  • SequenceStrategy : 가위바위보 순서대로 하나씩 내놓는다. (처음은 랜덤)
  • WinningStrategy : 하나를 내밀어 게임에 이기면 다음번에도 같은 손을 내민다. (처음은 랜덤)
  • RandomStrategy : 아무 손이나 완전히 랜덤하게 내민다
  • ProbStrategy : 랜덤하게 내밀지만, 이전 결과들의 승률을 반영하여 많이 이긴 손이 더 많이 나오도록 내민다.


그리고, 테스트용 main 함수들입니다.

  • Main.java : main() 메소드가 있는 테스트용 클래스. 소스를 수정하여 Strategy 를 선택할 수 있다.
  • Main2.java : main() 메소드에서 위의 4개의 Strategy를 배열에 넣고 모든 조합을 테스트한다.

 

아래는, Main2.java 실행결과입니다. 각각 3만번씩 실행하였으므로, 승률이 10000 보다 높으면 훌륭한 알고리즘이겠죠. 얼핏 보니, ProbStrategy의 승률이 들쑥날쑥하고, 대부분의 승률이 비슷합니다. 이렇게 승률이 비슷하다니 가위바위보가 상당히 우수한 게임이군요.

Pororo using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 0   loose: 0   draw: 30000
Thomas using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 0   loose: 0   draw: 30000
-----------------
Pororo using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 10113   loose: 9729   draw: 10158
Thomas using com.egloos.realmove.dp.strategy.RandomStrategy
win: 9729   loose: 10113   draw: 10158
-----------------
Pororo using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 10002   loose: 9999   draw: 9999
Thomas using com.egloos.realmove.dp.strategy.WinningStrategy
win: 9999   loose: 10002   draw: 9999
-----------------
Pororo using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 10058   loose: 9981   draw: 9961
Thomas using com.egloos.realmove.dp.strategy.ProbStrategy
win: 9981   loose: 10058   draw: 9961
-----------------
Pororo using com.egloos.realmove.dp.strategy.RandomStrategy
win: 10081   loose: 10016   draw: 9903
Thomas using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 10016   loose: 10081   draw: 9903
-----------------
Pororo using com.egloos.realmove.dp.strategy.RandomStrategy
win: 9993   loose: 9878   draw: 10129
Thomas using com.egloos.realmove.dp.strategy.RandomStrategy
win: 9878   loose: 9993   draw: 10129
-----------------
Pororo using com.egloos.realmove.dp.strategy.RandomStrategy
win: 10046   loose: 10043   draw: 9911
Thomas using com.egloos.realmove.dp.strategy.WinningStrategy
win: 10043   loose: 10046   draw: 9911
-----------------
Pororo using com.egloos.realmove.dp.strategy.RandomStrategy
win: 10041   loose: 9900   draw: 10059
Thomas using com.egloos.realmove.dp.strategy.ProbStrategy
win: 9900   loose: 10041   draw: 10059
-----------------
Pororo using com.egloos.realmove.dp.strategy.WinningStrategy
win: 10000   loose: 10000   draw: 10000
Thomas using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 10000   loose: 10000   draw: 10000
-----------------
Pororo using com.egloos.realmove.dp.strategy.WinningStrategy
win: 9955   loose: 9929   draw: 10116
Thomas using com.egloos.realmove.dp.strategy.RandomStrategy
win: 9929   loose: 9955   draw: 10116
-----------------
Pororo using com.egloos.realmove.dp.strategy.WinningStrategy
win: 29996   loose: 2   draw: 2
Thomas using com.egloos.realmove.dp.strategy.WinningStrategy
win: 2   loose: 29996   draw: 2
-----------------
Pororo using com.egloos.realmove.dp.strategy.WinningStrategy
win: 15456   loose: 2152   draw: 12392
Thomas using com.egloos.realmove.dp.strategy.ProbStrategy
win: 2152   loose: 15456   draw: 12392
-----------------
Pororo using com.egloos.realmove.dp.strategy.ProbStrategy
win: 10062   loose: 9964   draw: 9974
Thomas using com.egloos.realmove.dp.strategy.SequenceStrategy
win: 9964   loose: 10062   draw: 9974
-----------------
Pororo using com.egloos.realmove.dp.strategy.ProbStrategy
win: 10001   loose: 10005   draw: 9994
Thomas using com.egloos.realmove.dp.strategy.RandomStrategy
win: 10005   loose: 10001   draw: 9994
-----------------
Pororo using com.egloos.realmove.dp.strategy.ProbStrategy
win: 7521   loose: 9853   draw: 12626
Thomas using com.egloos.realmove.dp.strategy.WinningStrategy
win: 9853   loose: 7521   draw: 12626
-----------------
Pororo using com.egloos.realmove.dp.strategy.ProbStrategy
win: 9022   loose: 15115   draw: 5863
Thomas using com.egloos.realmove.dp.strategy.ProbStrategy
win: 15115   loose: 9022   draw: 5863
-----------------

by 선인장 | 2009/01/16 15:29 | 프로그래밍 | 트랙백 | 덧글(0)

Command Pattern

Overview

명령을 캡슐화 한다. cf. Strategy, State, Factory 패턴에서는 각각 알고리즘, 상태, 생성을 캡슐화 한다.

사용법이 Interpreter 패턴과 유사하기도 하다.

Roles

  • Receiver : 실제 action 수행
  • Command : execute() { givenReceiver.action() };
  • Invoker : setCommand()
  • Client : Invoker 에 Command 를 할당해서 호출

Usages

  • 근본적인 이점은 Invoker와 Receiver 사이의 연결이 느슨해졌다는 점에 있다. 더우기 그 느슨한 연결이 Command 객체로 캡슐화 추상화되어 여러 가지 부가 효과들을 얻을 수 있는 것이다.
    • 캡슐화된 Command를 logging 가능
    • 캡슐화된 Command를 store, restore 가능
      Oracle instance 처럼 command 를 caching 했다가 문제발생시 checkpoint 이후의 작업을 자동으로 복구할 수 있다.
    • 캡슐화된 Command 여러 개를 묶어 MacroCommand 생성 가능

Examples

  • 게시판의 쓰기, 삭제, 수정 등의 action 을 캡슐화
  • 그림판 프로그램에서, 그리기, 지우기, 배경색 지정, 필터 적용 등을 캡슐화
  • 계산기의 각각의 operator 를 캡슐과 가능할까? binary tree 구성한 이후의 실제 계산에서 사용 가능
  • Head First 의 리모콘 예제

by 선인장 | 2009/01/12 15:42 | 프로그래밍 | 트랙백 | 덧글(0)

Strategy Pattern

Summary

strategy(전략) = algorithm 을 교체한다.

Roles

Context using strategy.

strategy is Interface as abstractStrategy.

concreteStrategies implements strategy.

Usages

  • 느슨한 연결이므로 소스코드를 적게 수정하면서 알고리즘 교체.
  • 소스없는 라이브러리 형태로 제공될 경우에도 알고리즘 교체 가능하도록 코딩 가능.
  • 동적으로 알고리즘 교체 가능.

Examples

  • 가위바위보 게임에서 가위바위보를 내는 알고리즘 교체
  • 오목게임에서 다음 돌 놓은 위치 정하는 알고리즘 교체. (좀더 넓게 보자면, 위치 정할때 네트워크사용 또는 사용자action 을 사용하게 해서 게임을 만들 수도 있다)
  • 소팅 알고리즘을 여러 개 준비하여 교체.
  • 암호화 encrypting, decrypt 알고리즘 수정.

by 선인장 | 2009/01/12 14:37 | 프로그래밍 | 트랙백 | 덧글(0)

Abstract Pattern 예제

Overview

이런 형태의 주소록 데이터를 여러 가지 형식으로 출력할 수 있도록 코드를 작성하려고 합니다. 출력 형식은 계속해서 추가될 수 있으니 확장성을 고려하여 Abstract Pattern으로 작성하도록 하였습니다.

제가 작성한 출력 형식들은 오른쪽 이미지와 같습니다. 클릭하여 크게 확대할 수 있습니다.

Abstract Pattern이 무엇인지는 웹검색을 통해 쉽게 찾을 수 있으니 다시 설명하지 않겠습니다. 다만, Abstract Factory와 Abstract Product들이 있고, 실제로 그것들을 구현한 Concrete Factory와 Concrete Product 들이 있다는 것만 언급하겠습니다.

소스는 아래 3가지 방법 중 하나를 사용하여 구할 수 있습니다. JDK1.5 이상에서 컴파일 및 실행하세요.

 


Framework: Abstract One

파랗게 선택표시된 클래스들을 먼저 보시기 바랍니다. 중간쯤에 4개의 클래스를 가진 framework 패키지가 있습니다. 패키지 이름 그대로 기본 프레임워크 역할을 하는 패키지로서 4개의 추상 클래스들을 가지고 있습니다.

  • AbstractAddressBookFactory: AbstractFactory 역할. 나머지 3 클래스들을 생성할 수 있다. 각각의 Product들을 생성하는 createXXXX()메소드들은 추상메소드로 선언되어있어 subclass에서 이것을 구현해주어야 한다.
  • AbstractAddress: AbstractProduct 역할. 이름,전화번호,이메일을 저장하는 주소록레코드 클래스. 출력스트링을 생성하는 output() 메소드가 추상메소드로 선언되어 있어서 subclass에서 이것을 구현해주어야 한다.
  • AbstractGroup: AbstractProduct 역할. 주소록레코드들의 그룹. 위의 데이터에는 가족, 친구, 회사 그룹이 있다. 출력스트링을 생성하는 output() 메소드가 추상메소드로 선언되어 있어서 subclass에서 이것을 구현해주어야 한다.
  • AbstractAddressBook: AbstractProduct 역할. 그룹들을 가지고 있는 전체 주소록의 모델. 출력스트링을 생성하는 output() 메소드가 추상메소드로 선언되어 있어서 subclass에서 이것을 구현해주어야 한다.

최대한 유연한 확장성을 생각한다면 4개의 클래스 모두를 interface 로 만들어주는 것이 좋겠으나, 구현의 편의상 abstract class 로 작성하였습니다. 사실은 각각 interface 로 만들고, 편의성을 위해서는 그것을 implement한 abstract class 를 별도로 만드는 것이 바람직했겠죠. 하지만 그렇게 하면 코드 구조가 복잡해져서^^;;

Client: uses only framework

Tester 클래스는 Client역할의 클래스로서, main()메소드를 가지고 있고 그 안에서 각각의 클래스들을 생성하여 실행하게 됩니다. Factory 를 먼저 생성한 다음, 각각의 Product 들을 생성하는 방식으로 구동됩니다.

소스코드에서 확인하시다시피 Factory 를 생성할 때를 제외하면 framework 패키지의 abstract 클래스들만을 사용하고 있습니다. 즉 Client는 구체적인 구현내용은 알 필요 없도록 하는 것이 확장성을 최우선으로 하는 이런 류의 패턴들의 핵심이겠죠.

Factory 생성부분도 생성자를 직접호출하지 않고, Class.newInstance()를 사용하여 생성하였습니다. 클래스명을 스트링으로도 받아서 생성할 수도 있을 정도이니, 구체적인 Factory와는 극도로 느슨하게 결합되어 있다고 할 수 있을 것입니다.

출력양식 CSV : Concrete Ones #1

csv 패키지를 보시면 framework 패키지 클래스들이 똑같다는 것을 확인할 수 있습니다. Abstract 대신 Csv 가 사용된 것 뿐이죠. framework 들의 AbstractProduct 들이 output() 메소드를 구현하지 않고 추상메소드로 남겨두었으니, 이 ConcreteProduct 들에서는 output() 메소드를 구현해주면 되겠죠. ',' 와 '\n'으로 적당히 구분하여 내용들을 출력해주면 됩니다.

ConcreteFactory인 CsvAddressBookFactory의 구현은 더욱 간단해서 부연 설명이 필요 없겠네요.

출력양식 Others : Concrete Ones #2, #3 ....

XML 형태로 출력하는 클래스들을 만들어보면 어떨까요? 마찬가지로 framework 에 있는 클래스들을 거의 그대로 extends 해서 output() 메소드와 createXXX() 메소드들을 구현해주면 됩니다.

앞으로 나올 wiki 형식, html 형식으로 출력하는 클래스들도 전혀 다를 바가 없습니다.

이런 것이 바로 패턴과 framework 을 사용할때의 이점이겠죠. 규칙만 미리 알고 있으면 기능을 추가하는 일은 단순하고 기계적인 일이 됩니다. 코딩도 쉽고, 결과적으로 버그가 발생할 가능성도 그만큼 줄어듭니다. Eclipse 같이 Refactoring 기능이 잘 구현된 IDE를 사용한다면 훨씬 더 작업이 간단해질 것입니다. 제가 작업할때 약 2분 정도씩 걸리더군요.

출력양식 Text : More functionalities

Text 형식으로 출력해보죠. CSV 형식으로 출력하는 것과 동일한데, 이번엔 그룹명을 중간에 넣어볼까 합니다.그러러면 Address가 자신의 Group 정보까지 알고 있어야 할테니까 다른 출력양식을 추가할 때 했던 것 이외에 조금 더 수정이 필요할 것입니다.

After Coding

Abstract Pattern 을 사용하여 일종의 framework 를 구성해두면 이후에 기능을 추가하는 일이 아주 간단해지는 것을 확인할 수 있었습니다. 이 패턴을 포함한 몇몇 패턴들이 가진 큰 장점일 것입니다.

 

이 패턴이 흥미롭다고 느껴지면, 출력형식들을 계속해서 추가하는 일들을 할 수 있을 것입니다. 예컨대, 이 예제에서는 HTML 형식을 사용할 때 UL, Table 태그만 사용했지만, dt, ol 등 다른 태그로 구현할 수 있고, 모양도 다르게 출력할 수 있겠죠.

 

또한 이 패턴과 직접 관련은 없으나 Client 를 개선해가는 것도 재미있을 겁니다.

주소록 데이터를 파일이나 네트워크에서 얻어오도록 할 수도 있을 것입니다. 데이터를 애초에 XML형식으로 저장하고 XML 파서 내부에서 Product 들을 생성하게 하는 것도 재미있겠죠.

swing, awt, swt 등의 GUI 에 익숙해져 있다면, 좌측에 데이터, 우측에 출력창을 두고 데이터를 마음대로 변환할 수 있고, 출력형식을 선택하여 동적으로 출력이 이루어지도록 작업하는 것도 어렵지 않을 것입니다. 데이터가 변경될 때 출력에도 바로 반영되도록 하려면, Observer 패턴을 적용하면 더욱 좋겠네요.

 

제 경우엔 output() 메소드가 String이 아닌 OutputStream 을 반환하도록 설계하지 않은 것이 아쉽군요. 속도나 부하 등을 고려한다면 OutputStream으로 출력하는 것이 튜닝하기 훨씬 유리한 데다가, 출력시 인코딩을 다양하게 하려면 Stream이나 byte[]로 출력하는 것이 필수적일 테니까요.

현재 코드를 이렇게 고치려면 먼저 Stream 을 반환하는 getOutputStream() 메소드를 가진 AbstractProduct들을 만들어두고, 그것을 extends 한 ConcreteProduct를 하나하나 만들어가면 되겠죠. 혹시라도 String 반환하는 기존 시스템에서도 이용하고자 한다면, 양자를 이어줄 수 있도록 Adapter 패턴을 적용하는 건 어떨까 합니다.

by 선인장 | 2008/12/29 00:40 | 프로그래밍 | 트랙백 | 덧글(0)

어이없는 쇼핑몰들

카메라 충전기를 잃어버려, 충전기와 CPL 필터를 구매하려고 여러 쇼핑몰을 돌아다녔는데 큰 문제는 아니지만, 약간 어이없는 쇼핑몰들이 있군요.

dnshop 에 메인에 접속할 때, 팝업차단 되어있으면 이런 경고창이 뜹니다. "팝업 차단으로 불편하지 않으세요?..."

맞습니다. 팝업차단으로 상당히 불편했습니다. 처음 접속해서 저 경고창 없애느라 클릭 한 번 더 했는데, 회원가입 하고 나서도 또 떠서 다시 클릭하고, 로그인 하고 나서도 또 떠서 다시 클릭하고...
dnshop 말대로 팝업차단으로 인해 불편하긴 한데, 바로 그 경고창 때문에 불편했던 것입니다.

1. 페이지 오픈 팝업으로는 광고 밖에 안나온다는 것은 누구나 알고 있는 상식인데, 광고가 안떠서 불편한 것은 dnshop 이지 사용자들이 아닐 것입니다.
2. 만일 쇼핑시에 팝업창이 반드시 필요하도록 되어 있어서 정말 팝업을 허용해야 정상 사용이 가능하다면, 그것은 상식에 맞지않는 dnshop 기획서의 잘못이고 사용자 편의성을 위해 수정되어야 할 요소입니다. (이것 참... 네이트온 문자창도 팝업창허용 안되어 있으면 전송 후 그 결과를 볼 수 없는데... 민망하구만 ^^;;)




11번가 에서는 회원 가입할 때 아래와 같은 멘트가 있습니다.  "회원님의 개인정보 보호를 위해 실명확인을 실시하고..."
정확히 합시다. 실명확인은 웹사이트 마음대로 괜히 하는 것이지 개인정보 보호를 위해서 하는 것이 절대로 아닙니다. 생각해보세요. 쇼핑몰에서 구매자의 주민번호와 이름을 정확히 알아야 하는 경우는 전혀 없습니다. 아이디/비밀번호 잊었을 때에는 주민번호 말고도 확인할 수 있는 수단이 많습니다. 보호대상이자 대단히 중요한 개인정보인 주민등록번호를 불필요하게 받으면서 그것이 개인정보 보호를 위한 것이라니... 이런것을 적반하장이라고 하나요? 더 적당한 고사성어 같은 것 없을까요?

굳이 실명인증할 필요가 없는데도 굳이 받는 이유는 혹시 CRM 을 위한 그런 것 아닐까요? 11st 에서 수집된 정보가 SKT를 비롯하여 SK 타회사로 전달되어 마음껏 사용하려는 불순한 의도가 있는 것은 아닐까요? 예컨대, 11st 에서 자동차 용품을 구입한 사람을 대상으로 SK에너지가 이벤트를 한다던가, 11st 에서 여행용품을 많이 구매하는 사람을 대상으로 워커힐에서 이벤트를 한다던가... 물론 전혀 근거가 없는 단순한 가정일 뿐입니다.(혹시라도 아빠회사 관계자들이 보면 혼날까봐^^)

우리나라 웹사이트들에서 불필요하게 주민번호를 받고 있어서 문제라는 사실은 모든 사람들이 다 알고 있습니다. 회원가입시 주민번호를 받는 것이 너무 일반화 되어있어서, CRM같은 불순한 의도가 있는 것이 아니더라도 사이트 구축할때 회원정보에 주민번호를 저장하는 것을 당연히 여기고 있습니다. 그리고 나서 요즘 문제가 되니까, 부랴부라 주민번호를 암호화하고 정통부다 방통위에서 감사하겠다고 돌아다니고... 개인정보를 적절히 보호하고 있는가 하는 감사 이전에 주민번호 저장이 필수적이었는지부터 감사를 해야 하는것 아닐까 싶습니다.
많은 사람들이 모르고 있는 사실이 있습니다. 주민번호와 같이 모든 국민들에게 일련번호를 부여하여 관리하는 국가는 좀사는 나라 중에는 우리 나라 밖에는 없습니다. 그런 일련번호 없이도 다들 잘 돌아가고 있는데, 우리만 이런 번호체계를 가지고 있는 것이죠.(주민등록번호 제도가 만들어진 유래를 검색해보면 재미있더군요) 아무튼, 현재로서 모든 행정,공공 서비스의 마스터키인 주민등록번호를 아무나 수집해도 된다는 사실이 참 섬뜩합니다.



by 선인장 | 2008/10/21 10:37 | 네이트온 | 트랙백 | 덧글(0)

◀ 이전 페이지          다음 페이지 ▶