[Info]Tags categorized posts and contents patterns..

[AJAX] Ajax Code E xamples.. [Book] About the book.. [CSS] CSS Code E xamples.. [DB] Sql Code E xamples.. [DEV] All development stor...

2016년 4월 30일 토요일

[EP] SPRING CAMP 2016 을 다녀오다..

내 생에 첫 세미나이자 나 스스로의 의지로 참여한 세미나라고 할 수 있는 SPRING CAMP 2016 을 다녀왔다.. 

장소는 한국마이크로소프트[광화문 더케이트윈타워]였다.. 세미나 장소까지 가자니 주변역 중에서 광화문역이 그나마 5호선 라인이라 교통수단이 편리해서 그쪽으로 향했다.. 광화문쪽은 첨이기도 하고 더 케이트윈타워를 가는 것도 첨이라 그런지 조금은 어리버리 했지만 휴대폰으로 찍어둔 사진과 맵을 보면서 찾아갔다.. ㅋㅋㅋ 도착해보니 10시가 거의 다 되었었다..




도착을 해서 내 이름을 얘기하고 등록 확인을하고 나니 참가자라는 것을 증빙하는 팔찌와 기념품을 주셨는데 집에와서 찍어봤다.. 스티커가 훨씬 많았지만 내 기준에서 딱히 이쁘거나 맘에 들지 않는 것도 있었기에 눈에 들어오는 것들만 좀 가져왔다.. 그래도 저 물병은 쓸만할 듯.. ㅎㅎ [와이프가 본인이 쓴다고 해서 전달해준..]



선물을 받고서 건물내부를 요기 조기 기웃거리며 구경하며 기다리고 있으니 같이 듣기로 한 친구 B 군이 와서 같이 카페테리아를 좀 구경했다.. 알고보니 내가 있던 곳에서 옆으로 쭈욱 가면, 연결된 공간이었는데 난 엉뚱한 곳만 구경하고 있었다.. ㅋㅋㅋ.. 무엇보다 사이드쪽에 통로같은 곳에서 보는 뷰가 장난 아니었다.. 청와대, 광화문거리, 청사 등등 뷰가 어마어마 했다.. 살짝 마소[마이크로소프트] 직원들이 부럽긴했다.. ~_~..


10시가 넘을때 쯤 무엇인가를 한다고 방송이 나오길래 먼가 해서 세미나실쪽으로 들어가봤는데 LETS 라는 것을 한단다.. 이건 뭥미 하면서 우선은 세미나실에 자리를 잡았다.. 알고보니 LETS 라는 것은 본 세미나를 하기에 앞서서 간단하게 워밍업처럼 간단히 서로 토론할 수 있는 자유주제를 앞쪽에 게시하고 관심 있는 사람들이 모여서 자유토론을 하는 것이었다..









































무엇을 들을까 하다가 임성현 님이 하는 주제가 나에게 좀 맞기도 하고 관심이 가서 A 테이블 쪽으로 향했다.. 원래는 5~7명 정도 선에서 토론이 이루어지리라 생각을 하셨다고 하는데.. 왠열;; 인원이 엄청 많았다.. 인기가 장난 아니였다능.. ㅋㅋ.. 무튼 친구 B 군은 다른 곳에 관심이 간다고 그쪽으로 가고 나 혼자서 듣기 시작했다.. 듣는 중에 아웃사이더 햄을 만났다.. 어떻게 될지 모른다고 하셨는데 오셔서 사진을 열심히 찍고 계시는.. ㅋㅋㅋ.. 무튼 오랫만에 뵌거라 엄청 반가웠다..






























토론을 하시려고 하는 것은 위에 나온 구성처럼 신기술도입 , 이력서, 면접, 15년차 개발자 순이었다..

신기술 도입 가이드
신기술 도입에 있어서 어떻게 하면 조금 더 확실하게 순조롭게 도입이 가능하느냐를 위주로 설명하셨는데 큰 테두리 관점에서 간략히 보자면 도입하려는 신기술에 대한 필요한 것을 정리하는 기간[2주가 적당]에 대한 부분 그리고 도입하고자 하는 기술에 대한 자료 확인[실제 사용하는 해외 사이트를 이용] 마지막으로 활용방안에 대한 부분이었다.. 물론 중간에 더 단계가 있지만 간략화 했다..

지금 당장 내가 신기술을 도입을 하는 액션을 할 일은 없지만, 저렇게하면 조금 더 수월하면서도 착오를 덜 겪으며 신기술 도입이 가능할 거라는 생각을 들게끔 하였다.. 내 위치가 언제쯤 그리 될지 혹은 그런 상황이 발생할지는 모르겠지만 상당히 유익했다..

통과하지 못하는 이력서
해당 토론을 하기전에 질문을 하셨다.. "대기업용과 중소기업용의 이력서가 따로 있다고 생각하느냐..?? OX 퀴즈.." 나도 그랬고 대부분 그랬지만 당연히 대기업용이 있다에 손을 들었다.. 그런데 정답은 아니라고 하시더라..

우선 대기업은 이력서 필터링 시스템이 존재하고, 중소기업은 시스템이 존재하지는 않지만, 결국 대기업이 하는 필터링 시스템의 기준과 똑같다는 것이었다.. 즉, 기업의 규모에 상관없이 해당 업체에서 원하는 인재상에 어울리는 키워드가 이력서에 포함이 되어야지만 해당 필터링을 패스될 확률이 그나마 높다는 것이었다..

무엇보다 이력서는 너무 튀는 것보단 상대로 하여금 읽기가 쉬워야 하며, 개발자의 포트폴리오는 소스코드를 붙이거나 본인이 개발한 사이트 소개보단 프로젝트 내에서 무슨 역할을 했는지를 간단명료하게 소개하는 것을 추천하셨다.. 약간의 이력서의 주석같은 느낌이랄까..??

또한, 이력서 몇 장에 본인의 모든 것을 다 표현하기보단 더 자세한 얘기는 만나서 하자라는 뉘앙스를 본인을 보고 싶도록 하는 것이 좋다라고 하셨다.. 여지를 남겨야된다능..

그러면서 실제 기업의 예를 들어주셨는데 이력서 쓰는 연습이라고 해야될까..?? 패턴..?? 적인 측면에서 참고하면 좋을 만한 기업이 한화 그리고 SK 였다.. 나중에 함 봐야겠다..

나도 현재는 이력서를 종종 쓰기도 하고, 구직 전문 포털 사이트에 이력서를 올려두고 업데이트 하고 있지만 말씀하신 부분은 전혀 생각하지 못하고 써둔 것이기에 뜨끔하기도 했다.. 나도 내 이력서를 조금 더 업그레이드 하고 꼼꼼하게 고쳐나가야 겠다..

통과하지 못하는 면접
결과론적으로는 정답은 없는 듯 하다고 하신다.. 하지만, 어차피 사람 vs 사람의 관계에서 이루어지는 것이기에 진솔함을 잊지 말라는 것이 주된 핵심이였다..

무엇보다 본인이 하는 일 혹은 상대가 질문을 할만한 부분에 대해서 1차원적이 아닌 깊이 있게 질문에 대해서 생각을 해보라는 것이었다.. 3번정도의 질문에도 답을 할 수 있을 정도로 말이다..

이부분도 참 공감된 것이 나도 질문을 어느정도 예상하고 가지만, 막상가면 면접관은 왜?? 라는 질문이 계속 들어온다.. 근데 결국 막판에 답변을 못하게 되는 경우가 꽤 많다.. 이 부분도 나 스스로 꽤 준비를 하고, 생각을 많이 해야 될 듯 하다.. 특히나 자신이 하고 있는 일 자체에 대한 왜라는 질문.. 그게 중요하다고 본다..

15년차 개발자의 허와실
15년간 개발을 하시면서 느꼈던 점을 많이 얘기해주셨는데 아무래도 막판이고 시간이 좀 모자른 감이 있어서 급하게 마무리를 하셨다.. 하지만 많은 얘기를 해주신 것중에 가장 마음에 생각하고 새겨두면 좋다고 생각한 얘기가 있었는데..

"더 좋은 사람들과 더 오래 일하고 싶다.."

왜냐면 과거에는 그런 생각을 못했는데 언제부터인가 나도 약간씩 생각하게 된 부분이었는데 절대 공감하는 말이었다.. 일이란 것 자체가 혼자하는 것이 아니기에 본인만 잘났다고 되는것도 아니고 말이지.. 주변에 좋은 사람들을 두고, 더 오래 함께 같이 일을 하고 싶다는 생각을 하게 되는 요즘이다..

이렇게해서 LETS 가 끝나고 난 B 군과 점심을 먹었다.. 먹는중에도 우리 둘의 수다는 여전히 와다다다다.. 참.. 중간에 햄이 우리쪽으로 와서 칭구와 햄을 소개 아닌  소개를 해줬다.. ㅋㅋ.. 그렇게 순한척하는 B 군!! 완전;; 어이 없음 ㅡㅡ.. 우리는 식사를 다 하고서 난 세미나 신청할 때부터 계획한거처럼 Tack A 를 듣기로 하고 해당 세미나실로 이동했다.. 내가 Tack A 쪽을 들으려고 한 것은 특별한 이유는 없었다..

다만 내가 참여하는 첫 세미나였고, 다른쪽 파트는 대부분 중급 내지는 고급이었고, 들어본적이 없는 기술쪽의 얘기가 더 많았기에 그나마 초급에 해당하는 Tack A 를 선택하게 된 것이다.. 그리고 세미나가 이렇게 흘러간다라는 분위기도 살필겸..??













Tack A 는 위 시간표처럼 진행이 되었는데 난 솔직히 어떠한 기술을 알고서 듣는게 아니었기에 듣는 내내 공감대를 형성하진 못했다.. 무엇보다 말은 초급이라고 하지만 진짜 아무것도 모르는 초급보단 그래도 어느정도 베이스 지식이 있는 상태에서의 초급이라고 해야될까..?? 그런 성격이 더 강했던 것 같다..

그렇다고 나에게 있어서 무의미한 시간은 분명히 아니었고, 이런 기술이 있고 사람들이 이러한 관심을 갖고 발전해나가고 있구나 하는.. 지금의 트렌드라고 해야될까.. 나 스스로에게도 자극이 되고 그런 시간들이었다..

무튼.. 상황이 이러하다보니 본 세션에 대해서는 솔직히 정리할만한 건 없고, 각 세션별 간략한 소개와 발표자와 강의자료를 링크하려고 한다..

아샬 - TEST PATTERNS (초급)
단발 노랑머리가 인상적이셨는데 TDD, Unit Test 를 통해서 해결되는 부분 혹은 문제점에 대한 설명을 하셨다..

발표자료 : 업데이트 예정..
E-Mail : ahastudio@gmail.com

Kenny Bastani - BUILDING CLOUD NATIVE APPLICATIONS WITH CLOUD FOUNDRY AND SPRING (초급)
Pivotal 에 근무하는 직원으로 본인이 하는 일을 토대로 발표를 하셨는데 아무래도 영어이고, 옆에서 한국분[정윤진 님]이 통역은 해주셨지만 이해하기가 상당히 힘들었다..

발표자료 : 업데이트 예정..
E-Mail : kbastani@pivotal.io

이창재 - APACHE GEODE 와 SPRING DATA GEMFIRE (초급)
이분 역시 Pivotal 에 근무하는 직원으로 본인이 하는 일을 토대로 발표를 해주셨다..

발표자료 : 업데이트 예정..
E-Mail : jaylee@pivotal.io

이수홍 - DEEP DIVE INTO SPRING BOOT AUTOCONFIGURATION (중급)
경상도 사투리를 쓰셔서 그런지 상당히 친근감이 있었는데 목소리가 좋으셔서 그런지 발표자체는 귀에 상당히 잘 들어왔다..

발표자료 : 업데이트 예정..


My Comment..
나의 첫 세미나는 이렇게 끝났다.. 처음 갔었기 때문에 어리버리하기도 했고, 사진을 찍어도 되는것인가 싶어서 발표모습은 찍지도 못하기도 했다..

하지만 가길 잘했다는 생각을 하게 되었고, 맨 마지막 행사인 BOF 는 개인사정으로 참석을 못하게 되었는데 집에오기전에 라운지에 있는 아웃사이더 햄하고 잠시 얘기를 하였다..

기회가 있다면 이러한 세미나를 많이 참석하면 좋을 듯 하다.. 그리고 지금은 당췌 먼소린지 모르고 지나간게 태반이지만 시간이 지날수록 참여하게 되는 세미나에서 조금 더 이해도 하고, 더 얻어갈 수 있는게 많았으면 좋겠다..


모든 것이 그렇지만 그러면서 발전하는 것 아니겠는가.. 다음에는 이번 세미나를 발판삼아서 조금 덜 어리버리하고 더 관심도를 갖고서 재미나게 참여를 해보고 싶다..

무엇보다 첫 단추가 참 중요한데 첫 세미나가 규모도 나름 되고, 행상 진행패턴도 상당히 깔끔한 편이었고, 쉬는 신간에 먹을 수 있는 간식거리도 마음에 들었다.. 대규모 인원이 사용하다보니 세미나실이 오후에는 살짝 더웠다는 것만 빼고 말이지.. ㅋㅋㅋㅋ..

좋은 세미나를 만들어주신 SPRING CAMP 관계자 여러분 그리고 좋은 장소를 빌려주신 마소 관계자 분들 마지막으로 좋은 세미나가 되도록 열강을 해주신 발표자분들 모두 감사드립니다.. (__)


2016년 4월 28일 목요일

[Talk] 아흐 if else 잘 쓰자..

오늘은 개발건에 대한 반영이 있었다.. 그런데 반영이 되고서 문제가 좀 있었다.. 업무 자체는 되었지만, 로직에 대한 오류[실질적인 오류라기보단 위험도가 내재되어 있는 코딩] 때문이었는데 그 맹점은 if 문과 if else 문이었다..

웹 개발을 하면서 항상 쓰던 구문이고, 어찌보면 모든 로직의 기본이 된다고 볼 수 있는 문법이다.. 그런데 개발할 때는 왜 그게 안보였을까.. if 문이 여러번 존재하면, 한번씩 다 실행을 하지만, if else 로 하게 되면 A 또는 B 로 빠져서 어느 한쪽만 실행을 하게 된다..

구태여 불필요한 로직이 실행이 안된다는 것인데 또 항상 그렇게 써왔는데 바쁘게 해서 그런건지 아니면, 거의 퇴근 할 때 개발을 해서 정신 못차리고 했던건지..

if 문을 버젓하게도 4개를 연타로 써놨다.. 쓸데 없는 로직이 항상 돌게 된다.. 그런데 그 부분에 대한 것을 알아차리지 못하고 넘어간 것이다.. 헌데 오늘 현업하고 통화하면서 보니 그 부분이 딱!!! 눈에 들어오는것 아닌가 순간 멘붕이 오면서 머리가 멍해졌다.. 당연히 현업도 왜 이렇게 개발했냐고 다그치는데 이건 머 완전 대역 죄인이 따로 없다..

그 순간 모든 로직이 그냥 안보이는 상태가 되버려서 순간 빨리 작업을 해야되는데 하지를 못했다.. 내가 진정이 안되는 지경이니 서둘러서 주변에 계신 과장님께 잠시 같이 봐달라고 해서 같이 보면서 마음의 진정을 한 후에야 코딩을 했다.. 시간적으로는 많아야 5분 남짓인데 체감으로는 1시간 이상이 흐르는 듯 했다.. 하아 미춰버린다..

일전에도 나 스스로 조금 더 신경쓰고 하자고 글을 올렸는데 한동안 잠잠하다가 큰 실수를 하게 된것이다.. 조심하자 그러지말자.. 한 번 더 생각하고 약간의 생각만 더 하면 되는 것을 왜 그러지 못해서 진짜 복잡한 로직의 문제가 아닌 신입이나 할 법한 초보적인 실수를 하느냔 말이다..

내가 항상 조심하려고 하는 것중에 하나가 어찌보면 내 나쁜 버릇일지도 모르겠다.. 한 소스에 A, B ,C ,D 가 있다고 할 때 B 를 수정해달라고 하면, 4가지를 전체적으로 보면서 B 를 수정하는 것이 아니라 B 에만 집중해서 그것만 수정을 하면서 끝나버린다..

그러다보니 다시금 테스트를 하거나 전체적인 프로세스를 수행하면 B 수정으로 인해서 A, C, D 세 개와 상관관계가 틀어져서 오류가 발생하는 것을 종종 보게 된다.. [어찌 보면 당연한 오류일수도 있겠다.. 내가 자초한 것이니..]

앞으로 개발할 때는 너무 한 곳에 치우치는 것이 아닌 전체적으로 보도록 노력을 하자.. 아무리 소소한 것이라도 그렇게 해보자.. 안그러면 벌써 년차도 오래 됬는데 더 나쁜 습관으로 남게 될것이다..

특히나 로직을 들어가기에 앞서서 null 체크, length 체크, size 체크 등등 사전에 변수들로 인해서 문제가 생길법한 것들은 검증하는 부분을 꼭 필수로 넣어야 겠다..

하이고 미치겠다.. 실수를 할 수는 있지만, 할 법한 실수를 하자.. 그리고 다시금 누차 항상 말하는 것이고 나 스스로에게 요청하는 것이지만 마음의 여류를 갖고 업무를 하자..

오늘 조금 늦게 가고, 내 개인 일정을 조금 못하는게 좋지.. 누적된 실수로 형편없는 사람이 되거나 그 실수로 인해서 시스템 자체에 큰 누가 되는것이 더 문제 아니냔 말이다..

힘내자.. 나 스스로 알고 있고, 깨닫는 만큼 잘하자..



[Talk] 애드센스를 이용해보자..

블로그를 사용하면서 이것저것 클릭도 해보고 이건 먼가요.. 하면서 살펴볼 때가 종종 있다.. 아직도 많은 것을 모르다보니 사용하는 기능만 주로 사용하기는 한다.. 어차피 블로그의 목적 자체가 글을 올리는 것이기에 당연한거긴 하지만;; ㅎㅎ

그런데 수익이라는 카테고리에 애드센스라는 것이 보여서 클릭을 해봤다.. 요지는 본인의 블로그에 광고를 올리고 블로그에 방문한 사용자가 해당 광고 클릭 카운팅을 통한 수익을 정산해서 받는 그런 시스템인 듯 하다..

아는 것이 없으니 용가함게 무작정 클릭을 했다.. 본인 계정이 있으면, 그걸로 들어가고 아니면 새 계정을 만들면 된다고 하니 이것도 그냥 해봤다..



본인의 계정을 로그인해서 간략하게 이것저것 체크하고 넘어가고 나면 메일이 하나 온다.. 환영한단다.. 그리고 본인들이 기본 검토가 완료 되었지만, 추가적으로 최종 승인을 해주면 그 때부터 광고를 올리게 된다는 것인데.. 이게 당췌 먼소린지를 몰라서 요기조기 들어가서 클릭을 해봐도 광고는 안뜨고, 아놔.. 이거 하란건지 말란건지 ㅡㅡ.. 걍 짜증나서 반포기 상태였었다..
















그런데 오늘 뜻하지 않게 또 하나의 메일이 왔다.. 최종승인이란다.. 이게 먼지 ㅋㅋㅋ.. 무튼 머 승인 되었다고 하니 기분은 좋게 메일을 솨악.. 읽어보고서 애드센스 옵션쪽으로 다시 가봤다..






















우선은 아래처럼 권장사항이라고 하니 글 하단쪽하고 우측에 배너를 넣는 것으로 하고, 상세 설정에서도 사이즈를 지정해주고 하는데 난 그냥 응답형?? 이란 것으로 했다..


하고 나니 짜잔.. 아래처럼 진짜 광고가 나오더라.. 오른쪽하고 글 하단 이렇게 두곳에 말이지.. 근데 저걸 클릭해보고 싶어도 ㅡㅡ.. 어차피 링크겠지만;; 정책상 본인의 광고를 본인이 클릭해서 클릭 카운팅이 올라가는건 불법이라고 한다.. 내 블로그에 먼가 나오니까 신기해서 요리 저리 보기만 했다..




광고가 올라오고 나서 추가적으로 옵션 페이지를 가서 클릭도 해보고 먼가 설정을 바꿔보기도 했는데 아직은 잘 모르겠다 ㅡㅡ.. 돈은 어떻게 주는건지 어떤 경로를 통해서 받는건지.. 무슨 설정을 해야 나에게 유리하고 좋은 것인지..

우선은 새로운 것을 그 무엇인가를 시도해보고 기분이 좋아서 포스팅 해본 것이고, 혹시라도 정말 단 돈 10원!!! 이라도 수익이 나거나 알게 되는 것이 생긴다면 다시금 포스팅 해보리.. 이건 당췌 포스팅을 하려고 해도 내가 아는게 없다보니 해본 것까지만 올려본다..

그래도 왠지 모르게 재미쒀.. ㅋㅋㅋ..

[UFC] 코너 맥그리거 결국 UFC 200 제외..

출처 : SPOTV

화이트 대표는 27일(이하 한국 시간) 미국 방송 '굿모닝 아메리카'에 출연해 다니엘 코미어(37, 미국)와 존 존스(28, 미국)가 오는 7월 10일(이하 한국 시간) 미국 라스베이거스 T 모바일 아레나에서 열리는 UFC 200 메인이벤트에서 라이트헤비급 통합 타이틀을 놓고 싸운다고 발표했다. 화이트 대표는 지난 23일 미국 라스베이거스 MGM 그랜드가드 아레나에서 열린 UFC 200 홍보 기자회견에 불참한 페더급 챔피언 맥그리거에게 '괘씸죄'를 적용했다.

▲ 다니엘 코미어 vs 존 존스 공식 포스터 ⓒ UFC 트위터
▲ 다니엘 코미어 vs 존 존스 공식 포스터 ⓒ UFC 트위터


■ UFC 200 대진
[라이트헤비급 타이틀전] 존 존스 vs 다니엘 코미어
[페더급 잠정 타이틀전] 조제 알도 vs 프랭키 에드가
[여성 밴텀급 타이틀전] 미샤 테이트 vs 아만다 누네스
[헤비급] 케인 벨라스케즈 vs 트래비스 브라운
[웰터급] 조니 헨드릭스 vs 켈빈 가스텔럼
[미들급] 게가드 무사시 vs 데릭 브런슨
[라이트급] 디에고 산체스 vs 조 로존
[라이트급] 세이지 노스컷 vs 엔리케 마르틴
[라이트급] 짐 밀러 vs 고미 다카노리
[여성 밴텀급] 캣 진가노 vs 줄리아나 페냐

My Comment..
드디어 UFC 200 에 대한 최종안이 발표가 되었다.. 200 이라는 상징적인 부분 때문에 종합격투기 팬이라면 기대하는 이벤트기도 하고, 위 대진들을 봐도 다 흥미진진한 경기들 뿐이다..

그런데 그 중에서도 가장 사람들의 이목을 끈것은 누가머래도 코너 맥그리거 vs 네이트 디아즈 2차전 경기였을 것이다.. 이건 누구도 부정할 수 없을 것이다.. 그런데 결국 이렇게 되버렸다.. 본인이 너무 무리한 스케쥴 조정 요청을 했고, 데이나 화이트 입장에서는 코너 맥그리거 이외 모든 선수들에 대한 형평성 및 관리를 위해서 UFC 200을 제외하게 됬다.. 홍보도 홍보지만, 그를 통해서 엄청난 수익을 올릴수 있음에도 그렇게 결정을 내리게 된 화이트도 엄청 속이 상하긴 할 것이라고 생각한다..

나도 코너 맥그리거를 좋아하기는 하지만, 다른 모든 선수가 다 하는데 본인만의 특권을 갖는 것은 좀 무리였다고 생각이 들긴한다.. 해당 생각은 이전에 코너 맥그리거와 UFC 간의 힘겨루기라고 포스팅할 때도 언급한 바가 있다.. 무엇보다 다른 선수들의 생각도 크게 틀린 것은 없는 듯 하다..

  • 미샤 테이트"네이트 디아즈에게 복수하고 싶은 마음을 이해한다. 어떤 희생을 치르더라도 훈련에 집중하길 원했을 것이다. 그러나 이것은 계약의 문제다. 선수들은 대회 홍보에 대한 의무를 다해야 한다는 계약 조항에 사인했다"

  • 도널드 세로니"우리의 일은 사람들을 즐겁게 하는 것이다. (기자회견은) 이 직업의 일부다. 계약서에 사인하면 대회 홍보에 대한 의무를 다해야 한다. 나도 캐나다 오타와에서 열리는 UFC 파이트 나이트 89를 위해 인터뷰해야 한다. 내가 정말 원해서 하는 일 같은가? 해야 할 일 가운데 하나일 뿐"


아쉽지만, 우선 이번 이벤트에서는 접어두고, 메인 이벤트로 들어가게 된 존 존스 vs 다니엘 코미어 라이트 헤비급 통합 타이틀 전.. 흠.. 솔직히 난 다니엘 코미어를 좋아한다.. 존 존스는 항상 얘기가 나올 때마다 언급하는 것이지만 사생활도 경기 스타일도 싫어하는 선수 중 하나이다..

과거 1차전을 봤고, 기대를 했지만 존 존스를 넘기에는 코미어가 너무 역부족이라는게 보였다.. 그 때 당시 코미어는 그랬다.. "케인 벨라스케스와 훈련을 하지 못해서 자신을 한계점까지 밀어 붙일 선수가 없었다. 아쉬웠다." 라고 말이다..

하지만, 내가 보기엔 과연 정말일까?? 그 이유 하나일까?? 싶은게 솔직한 심정이다.. 코미어를 좋아하지만, 신체적인 조건 그리고 나이, 기술적인 부분 창의성 등등 모든 것을 감안해도 이번에도 코미어가 이기긴 힘들 듯 하다..

존 존스가 정말 싫지만, 마음은 코미어를 응원하지만, 결과적으로는 존 존스가 또 다시 통합 라이트 헤비급 타이틀을 가져 갈것이라고 보여진다.. ㅠㅜ

그리고 코너 맥그리거..!! 이상한 기행은 그만하고 어서 돌아와서 너의 멋진 모습을 보여달라규..!!!


[EP] Agile Korea 2012 #2..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

개인이 조직을 바꾸는 법 - 김창준
시작하면서  "조직장등이 아닌데 TDD를 팀에 도입하려고 하는 경우 한두달 정도 TDD에 대해서 공부를 한다"에 동의하는 사람이 손들어보라고 하시고는 여기에 손드는 사람은 이 발표가 도움이 될꺼라고 하셨다. 리스크라는 말이 있고 또 불확실성(uncertainity)이란 말이 있다. 리스크가 있는 상황은 여러 상황에 대한 대안이 있고 각각의 경우에 확률이 존재하는 경우고 불확실성은 상황에 대한 경우의 수도 모르고 그에 대한 확률도 모른다. 리스크에 대한 대처가 도움이 되는 대표적인 경우는 도박인데 현실에서는 불확실성의 경우가 훨씬 더 많다. 리스크 대처방안은 많이 존재하지만 리스크 대처방안을 불확실성에 적용해도 잘 안되기 때문에 불확실성에 맞는 대처방안이 따로 필요하지 않은가 하는 고민을 하기 시작했다.

그래서 실험을 진행했는데 10여개정도의 창업을 해본 창업자들과 MBA를 졸업한 사람을들 모아놓고 어떤 상황을 주고 선택을 하라고 하니까 창업자들과 MBA 졸업자들이 완전히 반대의 선택을 했고 창업자들과 포츈 100대 기업의 매니저들과 비교했을 때도 서로 반대의 선택을 했다. 이는 대기업은 안정적이기 때문에 리스크가 있는 상황에 비해 불확실성의 상황이 훨씬 적기 때문이다. 개인이나 조직에서도 불확실성의 경우가 훨씬 많고 성공한 중간 관리자들을 조사했을 때는 대부분 창업자들과 같은 전략을 취하고 있었다. 이 전략을 다음의 5가지로 정리했다.

  • Bird in Hand Principle : 지금 손안에 있는것 부터 시작한다는 의미로 방법중심인가 목표중심인가를 얘기한다. MBA은 좋은 목표를 정하고 가용한 방법 중에서 선택하지만 창업자들은 현재 가지고 있는 방법들을 가지고 무엇을 할 수 있는지를 결정한다. 예측가능한 경우에는 목표중심이 낫다. 앞에서 얘기한 TDD 도입은 목표중심이기 때문에 실패할 가능성이 높고 아는 것을 중신으로 해낼 수 있는 것을 생각하는 것이 좋다.
  • Crazy-Quilt Principle : 불확실할수록 사람을 끌여들여서 내편으로 만드는 것이 좋다. TDD를 도입하려고 한다면 사람을 모아서 같이 스터디를 하는 것이 좋다. 앞에서 얘기했듯이 혼자만 먼저 공부를 한다면 공부한뒤에 불리한 위치가 되기 쉽다. 여기서 불리한 위치라는 것은 먼저 공부했으므로 가르치는 위치가 되기 싶고 다른 사람들은 잘아는 사람이 옆에 있으므로 수동적이 되기 쉽다. 이런 경우는 대부분 실패한다.
  • Affordable Loss Principle : 감당할 수 있는 즉 잃을 수 있는 양을 정해놓고 그 안에서만 움직인다. 불확실한 상황속에서는 오래 살아남아야 하고 더 다양하게 선택할 수 있기 때문에 자신이 잃을 수 있는 양을 정해놔야 한다.
  • Pilot in the Plane Principle : 이는 비행기안에 조종사를 비유한 것인데 비행에서는 예측불가능한 상황이 많이 발생할 수 있지만 자동에 의존하지 않고 항상 파일롯이 비행기에 있는데 이는 예측을 할 수는 없지만 제어는 할 수 있다는 의미이다.
  • Lemonade Principle : 이는 레몬을 주면 레모네이드를 만들라는 의미이다. 뭔가가 주어졌을 때는(심지어 공격을 단하거나 피해의 상황이라고 할지라도) 그것을 이용한다.
이러한 전략을 조직을 바꿀때도 적용할 수 있다고 본다. 보통 애자일등을 조직내에 도입하려고 하는 사람이 오히려 변화할 수 없는 전략을 취하는 경우가 많다.

이번 세션도 10여분 정도의 짧은 세션이었다. 리스크의 상황과 불확실성의 상황을 따로 구분해서 생각해 보지는 않았기 때문에 꽤 인상적이었고(맨 처음에 손들어 보라고 할때 난 손을 들었다 ㅠㅠ) 나는 새로운 기술이나 방법론(혹은 새로운 서비스) 등에 관심이 많기 때문에 생각해 볼 여지가 많이 있었다. 한편으로는 항상 느끼는 거지만 김창준님은 이런 걸 어디서 어떻게 알아낼까 궁금하다.

유니콘 목장(The Unicorn Ranch) - 정기원
정기원님은 LAB80이라는 마이클이라는 개발자와 창업을 했고 디자이너로 국내에서 스타트업을 하면서 좋은 인재(이 발표에서는 유니콘형 인재라고 부른다.)를 찾다가 절망한 경험을 나누고 조언도 받기 위한 자리였다. 어떤 재능이 다른 재능보다 더 가치가 있는가? 하는 생각은 처음부터 어떤 재능이 다른 재능보다 낫다는 것을 전제하고 있다. 먼저 역사를 살펴보면 가로축을 여러가지 다른 분야로 나열하고 세로축을 그 분야를 위해서 필요한 것들로 나열했을 때 과거에는 수직으로만 움직이다가 르네상스 시대에는 수평축으로 여러 영역에 걸쳐서 활동했지만 산업혁명 이후에는 다시 수직적으로만 움직이고 있었다. 하지만 이제 다시 수평적으로 움직이려고 하고 있는데 이렇게 수평적으로 영역을 넓히는 사람을 보통 제너럴리스트라고 부르지만 여기서 말하려는 유니콘은 제너럴리스트과는 다르다.

그럼 유니콘은 무엇인가? 유니콘은 T자형 인재처럼 자신의 깊게 아는 영역이 있지만 그 외의 수평적으로도 넓게 알고 있으면서 각 역을 깊게도 알고 있는 사람을 유니콘이라고 부르고 스타트업에서는 이렇게 혼자서 다양한 영역을 커버할 수 있는 사람을 찾는다. 수평적이라고 함은 다른 영역의 사람과도 공감할 수 있는 사람을 의미한다. 유니콘을 T자형 인재보다 상위레벨로 보는데 피라미드 구조이기 때문에 유니콘은 많지 않지만 유니콘이 주는 가치는 엄청나다. 여기서 유니콘이라 함은 이미 유니콘인 사람과 현재는 T자형 인재이지만 유니콘으로 가기 위해서 노력하는 사람들을 의미한다. 현재 실리콘밸리의 구인광고를 보면 다양한 분야에 대해서 전문성을 가진 유니콘을 찾고 있는데 왜 다들 이렇게 유니콘을 찾는지를 이해하려면 지난 10년간 성공한 사람들을 살펴봐야 한다. 대표적인 대기업외에도 37signals53등의 회사등이 있는데 이러한 회사를 만들거나 합류한 사람들의 특성을 다음과 같이 정리할 수 있다.

  • Love your problem : 스스로 해결하고 싶은 문제를 푼다.(자신이 가려운 부분을 긁는다.)
  • Love your customers : 자신과 동일한 가려움이 있는 사람들이 있어야 한다.
  • Make Opinionated product : 가치관이 있는 제품을 만든다.
  • Cross-function : 하던 것만 반복해서는 이미 존재하는 것밖에 할수 없고 해보지 않은 다양한 분야를 해봐야 한다.
  • Learn Quickly : 이렇게 하려면 책이나 교과서를 읽고 할 시간이 없고 다른 사람들과 직접 해보거나 물어보면서 빨리 배울 수 있어야 한다.
  • Momentum-sensitive : 무엇이든 기세가 오를때가 있고 쳐질때가 있는데 이런 부분에 대한 감을 가지고 실제 제품에 적용해서 해결할 수 있어야 한다.
  • Quick Decisions : 스스로 결졍을 빨리 해야 한다.
  • Good communicator : 이렇게 하는 사람이 소통을 못할리가 없다. 빨리 배우고 찾는 사람은 자연히 소통을 잘하게 된다. 말을 잘하고 글을 잘 쓴다는 것은 생각이 간결하다는 의미고 이런 사람이 코드도 잘짜고 디자인도 잘한다.
유니콘은 경력이 아닌 세상을 바꾸고 개선하겠다는 태도에 달려있다. 이 유니콘들은 갑자기 생겨난게 아니라 사회에 대한 이해가 있는 사람들이고 이런 부분을 일일이 설명하거나 가르칠 필요가 없이 스스로 자기계발하고 혁신을 하고자 하고 빨리 배우면서 문제를 해결하고 모호함을 다룰 수 있는 사람들이다. 이 유니콘들은 만들 수 있는게 아니다. 즉, "요즘 이게 대세래. 우리도 다같이 유니콘이 되자"해서 되는게 아니다.


정기원님과 마이클은 자신들이 유니콘이라고 소개하셨고 유니콘들이 많은 IDEO, MIT 미디어 랩, 마이크로소프트 리서치등에서 일하다가 현재 LAB80을 서울에서 창업했다. 작년에 1년정도 세계를 돌면서 세계 각지에서 프로토타이핑을 해보다가 현재는 한국에 정착해 있다. 유니콘 목장들이 운영하는 방식은 대개 비슷한데 공통의 목표와 언어를 가지고 기본적인 구조와 프로세스를 정하는 환경을 조정하는 단계로 목표는 어디로 달릴지 방향을 정하는 것이다. 그리고 그 다음에는 각자 앞에서 정한 목표를 향해서 달린다. 이게 전부다. 국내에서 이러한 유니콘을 찾으려고 노력했지만 현재는 실패했고 유니콘이 없는 것인가 하는 절망에 빠져있다. 주니어를 뽑으려고 할 때 대부분 이들이 가장 싫어하는 3가지 말을 많이 했는데 스타트업에서 경력을 쌓아서 대기업으로 갈 것이라는 말과 새로운 것을 해야할 때 꼭 책으로 배우려는 것과 모르는 것을 물으면 대답을 회피하는 것이다.

인상적인 것으로 따지면 애자일 코리아에서 가장 인상적인 세션이었다. 이 세션을 들은 사람들은 대부분 비슷한 느낌을 받지 않았나 싶은데 "우린 유니콘인데 한국엔 유니콘 혹은 유니콘의 자질을 갖춘 사람이 없어"라는 약간 도발적인 말에 욱하는 억울함과 여러모로 매력적인 요소를 가진 LAB80에 대한 흥미일 것이다.(사실 이 욱하는 억울함은 금새 사라졌다.) 의도적인지 유하게 전달하는게 부족했는지는 모르지만 일단 정기원님의 목적은 어디서 유니콘을 찾을 수 있는지 혹은 어떻게 해야하는지 조언을 받고자 함이었고 많은 사람들이 이런 저런 얘기를 해주었다. 여러 얘기가 있었지만 LAB80이 아직 브랜딩이 제대로 안되어 있으므로 유니콘들이 관심을 가질 기회조차 없다는 것이었다. 그리고 쥬니어들을 뽑기 위한 과정에 대해서는 황상철님이 가르치는 방법이 잘못되지 않았는 생각해 볼 필요가 있다면서 당구도 300한테 배우는 것보다는 80한테 배우는게 낫다.라는 예를 드셨는데 귀에 쏙쏙 들어왔다.

나는 유니콘이라는 말을 여기서 처음 들어봤지만 인재형 자체는 내가 추구하는 인재형과 비슷하다.(내가 유니콘이라는 건 아니고..) 사실 듣고나서도 제너럴리스트와 유니콘과의 구분이 정확히 되지 않고 개발자인 내가 디자인, 마케팅 이런 부분까지 아울러야 한다는 건지 한 기술만 파지말고 다양한 기술을 파야 되는건지 좀 헷갈리기도 했다. 어쨌든 상당히 흥미가 가서 세션이 끝나고 나서 BOF에서도 정기원님 테이블에 가서 이런저런 얘기를 나누었지만 주로 유니콘을 어디서 찾아야 하는지 조언을 해드렸던것 같다.

Ephilogue
행사장인 전문 세미나 장이 아니라 MS의 세미나실이라서 약간 좁기는 했지만 이래저래 준비를 많이 하신 느낌이 많이 들었다. 작년에는 없던 로고부터 해서 중간 참석자네트워크에서 사용되는 고무팔찌에 음료수등의 간식이 들어있는 깨알같은 웰컴팩까지... 운영을 사실 불편하게 느끼지 않는다면 잘 느껴지지 않는데 자원활동가도 많아서인지 컨퍼런스는 부드럽게 잘 운영이 된것 같고 찬찬히 컨퍼런스를 보면 여러가지로 신경을 많이 쓴 티가 나는 컨퍼런스였다.


이번 컨퍼런스는 세션들이 전체적으로 흡족한 편이긴 했는데 또 막상 끝나고 생각해 보니 딱히 애자일에 대해서 많은 느낌을 받지 않았던 것 같다는 생각이 좀 들었다. 물론 이는 내가 세션 선택을 그런쪽으로 해서인지도 모르겠고 이번에는 스타트업 세션들이 포함되어서 좀 영역을 넓히려는 노력을 한게 아닐까 싶다. 애자일은 방법론(태도라고 해야하나?)에 관한 것이기 때문에 자바컨퍼런스나 루비컨퍼런스등에 비한다면 한가지 색을 가지기 어려운 면도 있지만 좀더 애자일적인 색체가 더 많이 묻어났으면 혹은 애자일 전파에 대해서 좀더 고민해 보는 자리였으면 하는 아쉬움이 있었다.(말했듯이 이는 내 세션선택의 따른 결과일 수도 있다.) 뭐 애자일 설명을 하고 그러면 너무 기초적인 내용이라 컨퍼런스에 참석한 사람에게는 지루할 수도 있으므로 어려운 문제라고는 생각한다.

아무튼 좋은 컨퍼런스를 단돈 몇만원에 참석해서 좋은 내용을 들어서 만족스럽다. 준비해주신 모든 분들께 감사의 말씀을 드리고 싶다. ㅎㅎ



[EP] Agile Korea 2012 #1..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

작년에 1회로 시작한 애자일 코리아 2012가 지난 토요일(1일)에 열렸다. 작년에도 가고 싶었지만 같은날 여러 컨퍼런스가 겹쳐서 참석못했는데 이번에는 참여를 했다. 이번 애자일 코리아는 포스코센터에 있는 마이크로 소프트의 세미나실에서 개최되고 프로그램은 다음과 같다.
사용자 삽입 이미지


(페르소나와 커뮤니케이션으로 풀어보는) 애자일을 실천하는 사람들이 겪는 어려움 - 최보나
작년 xper에서 활동도 많이 하시고 ThoughtWorks에서 일하시는 Analyst로 일하시는 최보나님의 세션이었고 (자기 소개하실때 소트웍스의 발음이 확 굴러가서 다른 회사인줄 알았;; 참고로 소트웍스는 마틴 파울러가 있는 회사다.) 커뮤니케이션에 대한 이야기였다. 시작할 때 T자형 인재와 A자형 인재에 대한 이야기로 시작하셨는데 T자형은 도요타에서 제시한 인재유형으로 익히 알다시피 하나에 깊은 지식을 가지고 있고 넓은 상식을 가지고 있는 인재형이고 A자형 인재는 T자형 인재유형에서 다른 사람들을 융합해 주는 커뮤니케이션 능력을 가진 인재유형을 말한다. 다음은 애자일 선언이다.

  • 프로세스나 도구에 앞서 개인과 상호작용을
  • 포괄적인 문서화에 앞서 작동하는 소프트웨어를
  • 계약 협상에 앞서 고객과의 협력을
  • 계획준수에 앞서 변화에 대한 대응을
여기서 관심가져야 하는 것은 상호작용이다. 상호작용을 잘하려면 어떻게 해야 하는가가 문제인데 커뮤니케이션이 답이라고 하셨다. 애자일을 하는 사람이라고 하면 항상 어떻게 하면 지금보다 더 나아질 수 있을까를 고민하고 해결해 나가는 사람이라고 생각한다. 그래서 애자일 프로세스를 적용해서 일하더라도 이러한 고민과 해결이 없으면 애자일이라고 부를 수 없다. 일을 할 때 다양한 역할의 사람들이 모여서 일을 하므로 다양한 커뮤니케이션이 필요해진다. 더군다나 이제는 한 조직 혹은 한 공간내의 사람들과 일하는 환경이 점점 적어지고 다양한 조직과 다양한 위치의 사람과 일을 하는 곳이 많아지고 있다. 이런 가운데 원활한 커뮤니케이션을 해야만 "동작하는 소프트웨어"를 만들 수 있다. 커퓨니케이션을 통해 해결해 가는 과정을 설명하기 위해 실제 소트웍스에서 있었던 사례를 중심으로 설명하셨다.

사례 1
신페이는 15명 팀에서 일하며 팀원들의 애자일 경험년수의 평균이 5년정도 된다. 팀원들은 개인역량이 뛰어나고 자기조직화가 잘되어 있어서 문제가 없을 줄 알았는데 신페이는 "이 프로젝트가 어디로 가고 있는가?"라는 고민을 시작했다. Analyst
[Analyst라는 역할이 국내에는 없기 때문에 정확히 이해는 안가지만 다른 분께 물어본바에 의하면 고객의 요구사항을 분석해주는 사람이라고 한다. 팀의 업무와 고객을 연결해주는 역할이 아닌가 싶다.]인 신페이는 각 팀원들이 정확히 무슨 일을 하고 있는지 알고 있지 못했다. 이를 해결해 주는 것이 1일 스크럼인데 각 팀원들이 각자 잘하다보니 스크럼은 뻔한 회의가 되었고 지루하고 의미없는 회의가 되어 그 중요성이 사라져 버렸다. 그래서 시각적인 회의를 도입해서 팀원들이 원형으로 앉아있는 것이 아니라 화이트보드를 바라보고 화이트보드에 스토리보드등 내용을 적어서 참여도와 집중도를 높였다. (시각적인) 커뮤니케이션이 답니다.

사례 2
필 클락은 미국과 인도로 나누어진 30명 정도의 팀에서 일하는데 여기에는 3개의 회사가 속해있고 팀원들은 애자일 경험도 별로 없었다. 이 팀의 문제는 사람들이 말이 안통한다는 것이었다.(언어가 다르다는 얘기는 아니다.) 비즈니스 하는 사람들이 하는 말을 기술자들이 제대로 이해못해서 결과물이 다르게 나오는게 문제였기 때문에 "테크니컬한 사람과 비즈니스하는 사람이 어떻게 소통할 수 있을까?"를 고민하기 시작했다. 그래서 BDD와 Cucumber를 팀내에 도입해서 비즈니스를 하는 사람들이 테스트와 인수테스트를 작성하도록 해서 개발자들이 완료의 기준을 정확히 잡을 수 있도록 했다. (도구를 이용한) 커뮤니케이션이 답이다.

사례 3
지납 난디는 10명 정도의 팀에서 애자일을 경험한 평균은 2-3년정도가 되는데 이 팀에는 소위 수퍼개발자라고 하는 사람들이 몇명있어서 문제가 생기면 누구나 이사람들에게 물어봐서 해결을 한다. 하지만 지납 난디는 이 수퍼개발자들이 오히려 고민거리가 되었는데 이 팀에서는 1일 스크럼 이후에 그날 누구랑 페어 프로그래밍을 할지를 추첨식으로 정해서 같은 사람과 계속 페어프로그래밍을 하지 않도록 하고 있었다. 수퍼개발자와 페어프로그래밍을 하게 되면 잘하는 개발자들이 그렇듯이 무수한 단축키로 빠르게 개발하면서 설명도 자세하게 하지 않기 때문에 오히려 더 어렵고 그 수준차이가 너무나서 오히려 자괴감이 들게 되어서 당일날 페어 프로그래밍의 짝을 선정하는 과정이 두렵게 느껴지기 시작했다. 그래서 이 팀에서는 일일 스크럽 이후에 1:1 피드백을 도입해서 매일 1:1로 커피먹으러 나가서 회고를 하도록 했다. 지납 난디와 같은 생각을 하던 사람들이 여럿이 있었기 때문에 이에 대한 얘기를 들은 수퍼개발자는 변하기 시작해서 설명도 자세히 해주고 페어프로그래밍에서 키보드도 다른 사람에게 내어주기 시작했다. (personal한 환경에서 하는) 커뮤니케이션이 답니다.

어려움에 부딪혔을 때는 문제의 답이 커뮤니케이션이 아닐까 고민해 봐야 한다. 보통 애자일을 도입하거나 프로세스를 확 바꾸는 것을 시도하기 쉬운데 의외로 많은 문제는 커뮤니케이션에 있고 이를 통해서 해결할 수 있다.

최보나님의 발표는 무난한 느낌이었다. 중요한 혹은 핵심적인 내용이 이런 경우가 많은데 너무 중요한 한편으로는 또 너무 뻔하기 때문에 어떤 임팩트를 주기는 어렵다. 자칫 지루하고 뻔할 수 있는 주제를 사례를 들어서 설명해서 흥미롭게 들을 수 있었다. 누구나 커뮤니케이션이 중요하다는 건 당연히 인지하고 있지만 의외로 또 쉽게 잊을 수 있는 부분이기도 하다. 사례처럼 간단히 문제가 해결되지는 않겠지만 그 과정자체가 커뮤니케이션인거니까... 다른 내용보다도 애자일 하는 사람은 지속적으로 개선하는 사람이라는 말이 인상적!

Lean Startup in Practice - 정지웅
클럽배닛의 CEO이신 정지웅님이 린 스타트업을 자사에 적용한 경험담을 나누어 주셨다. Eric Ries스타트업을 세상에 존재하는 문제를 해결해서 사업화하기 위한 특수한 목적을 가진 조직이라고 정의했고 스타트업은 그 반응을 증명하기 전에는 회사라고 부르기도 어렵다. 다시 말하면 불확실성속에서 많은 위험요인을 감수하고 세상에 존재하는 문제를 보다 명확히하고 그에 대한 해답을 찾아 시장과 고객앞에서 증명해내는 조직이라고 할 수 있다. 그래서 스타트업은 불확실성에 관한 것이고 새로운 실험적인 방법을 시도해 봐야하고 90%이상의 스타트업은 실제로 실패한다. 그럼 왜 실패하는가?가가 문제인데 대부분의 스타트업은 다음의 문제-해답-비용-타이밍의 4가지 요소에서 확실성을 확보하기 전에 모든 자원을 잃고 소멸되게 된다.

  1. 고객이 원하는 진짜 문제를 찾아내지 못함.
  2. 진짜 문제를 찾았더라도 그에 맞는 해답을 찾아내지 못함.
  3. 진짜 해답을 찾았더라도 그 해답을 증명하기 위해 너무 많은 비용을 소모.
  4. 많은 비용이 뒷받침되더라도 많은 시간을 소요해서 시장의 상황이 달라지면 문제와 해답은 모두 무효가 됨.
Frederick Winslow Taylor는 예상되는 문제를 모두 통제해야 한다고 했지만 예상할 수 없기 때문에 문제도 정의할 수 없다는 것이 문제다. 그래서 빠른 Pivot을 통해서 실패의 간격을 줄여간다면(주어진 자원과 금전이 모두 떨어지기 전에) 성공의 확률을 조금씩 올릴 수 있다는 것이 린스타트업이다. 대부분의 성공한 스타트업들은 최초 만들려던 것이 아닌 Pivot으로 전환한 제품을 통해서 성공을 이루어 냈다. 린스타트업의 원리는 이제 실리콘밸리에서 스타트업 기업의 경영기법과 철학으로 보편화되었고 Eric Ries는 IMVU의 창업자로 본인의 경험을 통해 린 스타트업이라는 개념을 만들어냈다. 린 스타트업은 더 적은 비용으로 자주 실패해서 결국 시장과 고객의 요구를 해결하는 것이 신규 사업이나 신규 서비스의 성공확률을 높이는 경영 및 프로덕트 개발방법이다.

폭포수 방법은 문제와 해결방법이 명확한 경우에 좋다. 정지웅님이 스타트업을 시작하면서 처음에는 1forMe라는 서비스를 만들었다 1forMe는 Etsy의 카피캣으로 핸드메이드 셀러마켓이었는데 핸드메이드를 하는 사람들이 다들 좋다고 해서 금새 셀러들을 모았는데 오픈하고 나니 국내에서는 핸드메이스 시장이 작어서 고객이 없었다. 이 문제를 못보고 폭포수 방법론으로 개발해서 런칭까지 한 후에 문제를 발견하고도 해결하는 대신 사이트를 리뉴얼 했었다. 두번째는 Torsto라는 서비스였는데 파워블로그들의 공동구매를 플랫폼화한 서비스로 이미 존재하는 문제를 비즈니스모델로 만들었다. 반응도 좋아서 오픈 첫날 매출이 천만원이나 찍었었지만 이제 사람들이 블로그의 공동구배를 믿지 않게 되는 분위기라 시장의 타이밍이 좋지 았았다. 하지만 pivot을 하지 않고 활성화를 해볼려고 폭포수 프로세스로 밀어붙였고 더이상 성장하지는 못하고 다른 서비스로 확장할 수 있는 모델도 아니었다.


애자일 방법론은 고객이 자신들이 원하는 것을 제대로 설명을 못하기 때문에 개발프로세스를 짧게 반복하면서 고객이 진정 원하는 것을 찾아내는 과정이다. 이와 비슷하게 린 스타트업은 불확실한 문제를 점진적으로 검증하면서 그에 맞는 해결책을 함께 만들어나가는 비즈니스 방법론으로 시장조사에 기초해서 애자일 프로세스를 적용하고 시장소자 데이터나 상황이 달라지만 애자일 프로세스를 재 적용한다. 언제든지 달라질 수 있기 때문에 ongoing review하고 ongoing development한다. 무엇이 맞는지에 대한 보장이 없으니 핵심만으로 아이디어를 빨리 구현하고 실제 수치를 측정한다. 사용자의 의견같은거 말고 수치로 측정할 수 있는 데이터를 만들로 린으로 검증하는 과정을 방복한다.

IDEAS 과정에서는 무엇이 문제인지 알수 없으므로 계속 회의하지만 아이디어단계에서는 답이 나올 수 없다. BUILD 과정에서는 빨리 오픈하고 빨리 피드백을 받아야 한다. 중요하지 않은 기능을 다 제거해야 하는데 중요한 기능을 생각하는 것보다 훨씬 적을 수 있기 때문에 가장 중요한 것에 집중하고 나머지는 계속 버려나가는 과정을 반복해야 한다. MEASURE 단계에서는 객관적인 지표를 뽑아내야 한다. 각자 선호하는 것들이 있지만 여기서 필요한건 객관적인 지표이다. 수많은 지표들이 있는데 무엇이 중요한지를 결정해야 하고 지표를 실제로 A/B 테스팅등으로 확인해 보고 사용자의 피드백을 받아야 한다. 린 스타트업의 원리는 답을 알기힘든 큰 변화를 추구하는 개인이나 신규 서비스를 만드는 소규모 조직이나 신규 사업을 하는 내부 조직등 어디나 적용할 수 있다. 실제 적용할 때는 pivot을 하는 용기를 내는 것이 정말 중요하고 pivot을 하는 것은 생각보다 어렵다.

개인적으로는 오랜만에 정지웅님을 뵙게 되서 반가운 세션이었다. 몇번 얼굴을 뵌 적이 있어서 SNS에서 소식은 듣고 있었는데 사실 클럽베닛이 이렇게까지 성공을 하고 있는 줄은 몰랐다. 이 세션은 개발에 대한 세션이라기 보다는 스타트업의 프로세스에 대한 세견이었지만 이런쪽에 대해선 잘 모르기 때문에 더욱 흥미로왔다. 린 스타트업책은 한번 읽어봐야겠다.(번역서 얘기를 들은것 같은데 검색해봐도 못 찾겠다. ㅠㅠ) 일단 몇년간 실패를 한 경험은 나눈 세션이라서 알차고 좋았다.


ATDD: 스펙도 애자일하게 쓰자 - 황상철
스펙을 제대로 작성하는 것은 구식이다?에 나오는 "스펙을 한번이라도 제대로 작성해 본적이 있는가?"라는 글을 보시고 발표를 하기로 했다고 하셨다. 스펙(Specification)은 문서나 다이어그램 등이 있는데 그럼 스펙은 언제 얼마만큼 작성해야 하는가? 황상철님은 스펙은 개발전에 쓰고 개발을 할 수 있으면 멈추면 되고 다시 개발을 할 수 없게 되면 스펙을 쓰면 된다고 하셨다.(표준이나 WBS등이 중요한게 아니다.) 스펙 작성에는 대표적으로 UML이 있는데 오랫동안 UML을 가르쳤지만 여태까지 UML을 잘 쓰는 개발자는 한번도 본적이 없다고 하셨다. 그럼 개발자가 UML을 잘 모르는게 잘못인가생각하면 그렇지는 않다. 보통 UML은 너무 복잡하기 때문에 개발자들은 잘못 그릴까봐 오히려 안그리게 된다. 그 외에 유즈케이스가 있는데 유즈케이스는 코드수정에 따른 버전업이 문제다.


그러면 스펙과 코드가 일치하지 않는 것이 정말 문제인지 생각해 보자. 문제라고 가정해보면 Specification by Example에서 제시한 Living Document가 대안이 될 수 있는데 여기서 얘기하는 스펙은 코드와 시스템을 의미한다. 스펙에 해당하는 코드는 JUnit등으로 작성한 유닛테스트나 Cucumber등으로 작성한 테스트가 있고 이것을 시스템(specflow)으로 만들 것을 제시하고 있다. 그럼 문제가 아니라고 생각하면 어떤가? 스펙도 우유처럼 유통기한이 있어야 한다. 스펙을 어떤 기간동안의 스냅샷으로 보고 그 기간동안만 맞추면 되고 그 이후에는 코드로 보면 된다. 현재 하고있는 nForge 프로젝트에서는 Markdwon으로 스펙을 쓰고 있는데 팀원들이 다양한 OS를 사용하고 있기 때문에 어디서나 쉽게 작성하고 출력을 자유롭게 할 수 있기 때문에 Markdown을 선택했다. 스펙에는 반드시 완료조건(AC, Acceptable Condition)을 적어서 개발이 완료되어야 하는 조건을 명시하고 있다. 스펙에 AC를 잘 작성해 놓으면 테스트 시나리오는 대부분 커버할 수 있다. 추가적으로 테스트를 피라미드로 나타내면 맨 아래 유닛테스트가 있고 그 위에 서비스테스트가 있고 가장 위에 UI 테스트가 있다. UI 테스트가 제대로 이득을 보지 못하는 이유는 서비스 테스트를 제대로 하지 않기 때문이라고 생각하는데 보통은 유닛테스트를 작성한 다음에 UI 테스트를 작성하곤 한다. 서비스 테스트의 영역을 넓히는 것이 좋다.

다른 세션에 비해선 짧은 세션이었다.(20분 정도였나?) 이 세션을 듣고 생각해 보니 나는 스펙을 작성해 본 적이 없다. 예전에 회사에서는 CMMI 한다고 문서들을 만들기도 했지만 그건 보여주기 문서였지 사실 개발을 위한 문서는 아니었다. 그래서 처음에 들을 때 이 스펙을 나는 기획서라고 생각하고 있었다.(어떤 의미에선 비슷하기도 하지만 어쨌든 기획서를 보고 개발을 하기 때문에) 사실 문서화를 좋아하는 편은 아닌데(코드에 문서가 섞이는걸 더 선호한다.) 세션을 듣다 보니 개발자가 개발할 내용을 확실히 하기 위해서 적는 것을 스펙으로 이해했고 저런 문서를 개발자가 정리하면 개발영역도 명확하고 다른 사람들과 의논하기에도 괜찮겠다는 생각이 들었다. 담에 해봐야지...

[Book] 드리밍 인 코드..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

드리밍 인 코드 - 8점
스콧 로젠버그 지음
황대산 옮김
에이콘출판

드리밍 인 코드는 챈들러 프로젝트가 프로젝트가 겪는 과정을 에세이처럼 풀어가면서 소프트웨어 업계의 한 단면을 들여다 보는 책이라고 할 수 있다. 챈들러(Chandler) 프로젝트는 로터스 1-2-3으로 엄청난 성공을 거둔 미치 케이퍼(Mitch Kapor)가 2002년 OSAF (Open Source Applications Foundation)를 만들어서 소위 PIMS(Personal Infomation Management System)라고 부르는 개인정보관리를 해주는 소프트웨어를 만들기 위해서 시작된 프로젝트다.

시작은 소프트웨어는 왜 대부분 실패하는 가부터 시작한다. 지금도 그렇지만 수많은 프로젝트들은 완전히 실패하거나 일정을 지연하거나 완성도가 떨어지는 경우가 허다하다. 이러한 문제를 바꾸기 위해서 많은 시도들이 있었지만 아직까지 시원하게 해결한 문제는 없다. 소프트웨어 역사에 실패사례들이 많이 있지 수많은 개발자들은 이를 잊고 자신은 다를꺼라고 생각하면서 시도한다. 케이퍼도 이렇게 시작했고 기존의 문제들을 자신이 직접 해결하려고 시작했다.

마침 케이퍼의 엄청난 자산을 기반으로 OSAF에서 뛰어난 개발자들이 수없이 참여하고 시작할때 이목이 집중되었지만 기대와 다르게 목표로했던 일정은 계속 지연되기 시작했고 해결해야 할 문제들은 해결되지 않고 기능은 점점 축소되어 가고 있었다. 이 프로젝트에 참여했던 스콧 로젠버그가 챈들러프로젝트에서 어떻게 협의하고 어떤 문제들을 가지고 해결하거나 타협해 나갔는지를 보여주고 있다. 스콧 로젠버그가 3년동안 본 모습을 책에 적었고 그 당시에도 챈들러는 실패할 것처럼 보였다.(지금은 v1.0.3까지 나와있었지만 세상에 임팩트를 주기엔 늦어버렸다.) 스콧 로젠버그는 흥미롭게 챈들러의 과정을 설명하면서 소프트웨어 개발이 왜 어려운지에 대한 문제와 그 문제를 해결하기 위해서 어떤 노력들이 있었는지 나열하고 있다.

챈들러 프로젝트의 역사와 함께 소프트웨어 개발의 역사를 보는 듯한 느낌이다. 내가 인상깊었던 것은 미치케이퍼다. 수년간의 어려움과 실패가운데서도 그는 프로젝트를 그만둘 생각을 하지않고 자신의 신념을 밀어붙혔다.(물론 그만한 돈이 있었지만...) 성공과 실패를 나누는 많은 견해가 있었지만 성공적인 챈들러의 런칭이라는 점에서는 실패라고 할 수도 있겠지만 소프트웨어 역사에서 챈들러가 남긴 것은 많다고 생각한다. 그런면에서 실패는 아니라고 본다. 책에도 나오지만 이 책에서 케이퍼는 모질라와의 인연을 갖게 되어 모질라를 후원하고 모두가 알다시피 모질라는 성공적으로 파이어폭스를 릴리즈했다. 챈들러나 OSAF가 없었다면 파이어폭스도 없었을 지 모른다.

스콧 로젠버그는 프로그래머가 아닌 사람도 대상으로 책을 썼다고 했지만 프로그래밍에 대한 얘기가 많이 나오기 때문에 프로그래머가 아니라면 재밌을지 잘 모르겠다. 하지만 프로그래머라면 상당히 흥미로운 얘기로 가득한 책이고 단순히 재미위주로만 읽는 것이 아니라 소프트웨어 개발이라는 점에서 참고하고 생각해 볼만한 내용들로 가득하다. 이 책에서 인상적인 몇가지 내용을 적어놓는다.

성공적인 프로세스는 재사용될 수 없다. 은총알은 재장전이 불가능하다.

나는 방법론 전도사들이 사기꾼이라고 생각하지는 않지만 그들은 필연적으로 과거 지향적일 수밖에 없다. 그들은 오늘날의 소프트웨어 산업이 당면한 어려운 문제를 해결하기 위한 해법을 제시하지만, 다음 세대의 문제들이 쏟아지기 시작할 때는 별 도움을 주지 못할 것이다. 어쩌면 그게 10년을 주기로 새로운 방법론들이 등장하는 이유일지도 모른다.

그들은 예술가들이 예술 작품을 만드는 작업에 도움이 되도록 몇 가지 효율적인 도구를 마련해 주기로 결정했다. 그들은 전동 조각칼, 자동으로 물감 짜내는 기계 등을 발명했다... 결과물은 여전히 만족스러운 수준에 이르지 못했다.. 협회는 2주 동안 특정 그룹의 화가들이 하루에 평균 몇 번의 붓질을 하는지를 세어봤고, 이러한 기준을 나머지 화가들의 가치를 평가하는 데 적용했다. 만약 어떤 화가가 하루에 20번 미만의 붓질을 했다면 그는 명백히 생상성이 낮은 화가였다. 안타깝게도 이러한 지식의 진전은 실제로 예술 작품을 제작하는 일에 별 영향을 미치지 못하는 듯 보였다. 마침내 그들은 근본적 어려움이 관리에 있다고 결론 내렸다. 재능있는 학생 중 한명(레오나르도 다빈치란 이름의)이 곧바로 물감, 캔버스, 붓 등을 조작에 조잘하는 일을 책임지는 관리자로 승격했다.


2016년 4월 25일 월요일

[JAVA] 6장 유효성검사(validation), 데이터 바인딩, 타입 변환 #2..

출처 : Outsider's Dev Story https://blog.outsider.ne.kr/

이 문서는 개인적인 목적이나 배포하기 위해서 복사할 수 있다. 출력물이든 디지털 문서든 각 복사본에 어떤 비용도 청구할 수 없고 모든 복사본에는 이 카피라이트 문구가 있어야 한다.a

6.5 Spring 3 타입 변환
스프링 3는 일반적인 타입변환 시스템을 위해 core.convert 패키지를 도입했다. 타입변환 시스템은 타입변환 로직을 구현하는 SPI와 런타임시에 타입변환을 실행하는 API를 정의한다. 스프링 컨테이너에서 구체적인 빈 프로퍼티값을 필요한 프로퍼티 타입으로 변환하는 프로퍼티 에디터 대신에 타입변환 시스템을 사용할 수 있다. 어플리케이션내에서 타입변환이 필요한 어디서든 퍼블릭 API를 사용할 수 있다.

6.5.1 Converter SPI
타입변환 로직을 구현하는 SPI는 간단하고 강타입(strongly typed)이다.


1
2
3
4
5
6
7
8
9
Java

package org.springframework.core.convert.converter;

public interface Converter<S, T> {

  T convert(S source);

}

자신만의 Converter를 만들려면 위의 인터페이스를 구현하면 된다. 파라미터 S는 변환되기 전의 타입이고 파라미터 T는 변환할 타입이다. convert(S)를 호출할 때 source 아규먼트는 null이 아니라는 것을 보장해야 한다. 작성한 Converter는 변환에 실패했을 때 Exception을 던질 것이다. source의 값이 유효하지 않은 경우 IllegalArgumentException을 던져야 한다. 작성한 Converter 구현체가 쓰레드 세이프하도록 해야 한다.

core.convert.support 패키지에 핀리한 여러 가지 컨버터 구현체가 있다. 이 구현체들은 문자열을 숫자나 다른 일반적인 타입으로 변환하는 컨버터가 포한되어 있다. Converter 구현의 예제로 StringToInteger를 보자.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Java

package org.springframework.core.convert.support;

final class StringToInteger implements Converter<String, Integer> {

  public Integer convert(String source) {
    return Integer.valueOf(source);
  }

}

6.5.2 ConverterFactory
String을 java.lang.Enum 객체로 변환하는 등 전체 클래스 계층에서 변환로직을 한 곳에 모으려고 한다면 ConverterFactory를 구현해라.

1
2
3
4
5
6
7
Java

package org.springframework.core.convert.converter;

public interface ConverterFactory<S, R> {
  <T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

파라미터 S는 변환하기 전의 타입이고 파라미터 R은 변환할 클래스의 범위를 정의하는 기본타입이다. 이제 getConverter(Class<T>)를 구현해라. T는 R의 슈퍼클래스다.
StringToEnum ConverterFactory 예제를 보자.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Java

package org.springframework.core.convert.support;

final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {

  public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
    return new StringToEnumConverter(targetType);
  }

  private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {

    private Class<T> enumType;

    public StringToEnumConverter(Class<T> enumType) {
      this.enumType = enumType;
    }

    public T convert(String source) {
      return (T) Enum.valueOf(this.enumType, source.trim());
    }
  }
}

6.5.3 GenericConverter
세련 된 Converter 구현체가 필요하다면 GenericConverter 인터페이스를 고려해봐라. 훨씬 유연하면서도 타입 제약이 적은 GenericConverter는 여러 가지 타입의 소스와 타겟간의 변환을 지원한다. 게다가 GenericConverter는 자신만의 변환 로직을 구현할 때 소스와 타겟 필드 컨텍스트를 사용할 수 있게 해준다. 이러한 컨텍스트로 필드 어노테이션이나 필드정의에 선언된 제너릭 정보로 타입변환을 할 수 있다.

1
2
3
4
5
6
7
8
Java

package org.springframework.core.convert.converter;

public interface GenericConverter {
  public Set<ConvertiblePair> getConvertibleTypes();
  Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}

GenericConverter를 구현하려면 지원하는 source->target 타입의 쌍을 반환하는 getConvertibleTypes()를 정의하고 변환 로직을 위해 convert(Object, TypeDescriptor, TypeDescriptor)를 구현한다. 소스 TypeDescriptor는 변환될 값이 있는 소스 필드에 접근하게 해주고 타겟 TypeDescriptor는 변환된 값이 할당될 타겟 필드에 접근하게 해준다.

자바 배열과 컬렉션을 변환해주는 컨버터는 GenericConverter의 좋은 예제다. 이 ArrayToCollectionConverter는 컬렉션의 엘리먼트 타입을 위한 타겟 컬렉션 타입을 선언한 필드를 가진다. 이는 타겟 필드에 컬렉션을 할당하기 전에 소스 배열의 각 엘리먼트를 컬렉션 엘리먼트 타입으로 변환한다.



Note
GenericConverter은 훨씬 복잡한 SPI 인터페이스이므로 필요할때만 사용해야 한다. 기본적인 타입 변환이 필요하다면 Converter나 ConverterFactory를 사용해라.

6.5.3.1 ConditionalGenericConverter
때 로는 지정한 상태가 참일 경우에만 Converter를 실행하고 싶을 것이다. 예를 들어 타겟 필드에 어노테이션을 지정했을 때만 Converter를 실행하고 싶을 것이다. 또는 정적 valueOf 메서드처럼 지정한 메서드가 타켓클래스에 정의되었을 때만 Converter를 실행하기를 원할 것이다. GenericConverter의 하위인터페이스인 ConditionalGenericConverter는 이러한 커스텀 크리테리아 검사를 정의할 수 있다.


1
2
3
4
5
Java

public interface ConditionalGenericConverter extends GenericConverter {
  boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}

퍼시스턴트 엔티티 식별자와 엔티티 참조간의 변환을 하는 EntityConverter가 ConditionalGenericConverter의 좋은 예이다. 이러한 EntityConverter는 타겟 엔티티 타입이 정적 finder 메서드(예: findAccount(Long))를 정의했을 때만 수행된다. matches(TypeDescriptor, TypeDescriptor)의 구현체에서 이러한 finder 메서드 검사를 수행한다.

6.5.4 ConversionService API
ConversionService는 런타임시에 타입 변환 로직을 실행하는 통일된 API를 정의한다. 때로는 이러한 퍼사드 인터페이스뒤에서 컨버터가 실행된다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Java

package org.springframework.core.convert;

public interface ConversionService {
  boolean canConvert(Class<?> sourceType, Class<?> targetType);

  <T> T convert(Object source, Class<T> targetType);

  boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);

  Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}

대부분의 ConversionService 구현체는 컨버터를 등록하는 SPI를 제공하는 ConverterRegistry도 구현하고 있다. 내부적으로 ConversionService 구현체는 타입변환 로직 수행을 등록된 컨버터에 위임한다.

신뢰할 수 있는 ConversionService 구현체는 core.convert.support 패키지에 있다. GenericConversionService는 대부분에 환경에서 사용할 수 있는 범용적인 구현체이다. ConversionServiceFactory는 공통적인 ConversionService 설정을 생성하는 편리한 팩토리를 제공한다.

6.5.5 ConversionService 설정
ConversionService 는 어플리케이션 구동시에 인스턴스화되고 여러 쓰레드 사이에서 공유되도록 설계된 무상태의 객체이다. 스프링 어플리케이션에서는 보통 스프링 컨테이너(또는 ApplicationContext)마다 ConversionService 인스턴스를 설정한다. 설정한 ConversionService를 스프링이 선택해서 프레임워크가 타입변환을 수행해야 할 때마다 사용할 것이다. 이 ConversionService를 어떤 빈에라도 주입해서 직접 호출할 수도 있다.



Note
스프링에 등록된 ConversionService가 없으면 원래의 PropertyEditor기반 시스템을 사용한다.

conversionService id의 다음 빈 정의를 추가해서 스프링에 기본 ConversionService를 등록한다.


1
2
3
Xml

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"/>

기본 ConversionService는 문자열, 숫자, 이넘(enums), 컬렉션, 맵 등의 타입을 변환한다. converters 프로퍼티를 설정해서 자신의 커스텀 컴버터로 기본 컨버터를 보완하거나 오버라이드할 수 있다. 프로퍼티 값은 Converter, ConverterFactory, GenericConverter 인터페이스를 구현할 것이다.

1
2
3
4
5
6
7
8
9
Xml

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
  <property name="converters">
    <list>
      <bean class="example.MyCustomConverter"/>
    </list>
  </property>
</bean>

스프링 MVC 어플리케이션에서 ConversionService를 사용하는 것도 일반적이다. < mvc:annotation-driven/>로 사용하는 방법은 Section 6.6.5, “Spring MVC에서의 포매팅 설정”를 봐라.

변환하는 과정에서 포매팅을 적용해야 하는 경우도 있다. FormattingConversionServiceFactoryBean를 사용하는 방법은 Section 6.6.3, “FormatterRegistry SPI”를 봐라.

6.5.6 프로그래밍적인 ConversionService의 사용
다른 빈에 ConversionService 인스턴스의 참조를 주입해서 프로그래밍적으로 ConversionService 인스턴스를 사용할 수 있다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Java

@Service
public class MyService {

  @Autowired
  public MyService(ConversionService conversionService) {
    this.conversionService = conversionService;
  }

  public void doIt() {
    this.conversionService.convert(...)
  }
}

6.6 Spring 3 필드 포매팅
이전 섹션에서 얘기했듯이 core.convert는 범용적인 타입변환 시스템이다. 이는 한 타입에서 다른 타입으로 변환하는 로직을 구현하는 강타입의 Converter SPI처럼 통일된 ConversionService API를 제공한다. 스프링 컨테이너는 빈 프로퍼티의 값을 바인딩하는데 이 시스템을 사용한다. 게다가 스프링 표현언어 (SpEL)와 DataBinder는 둘 다 필드 값을 바인딩 하는데 이 시스템을 사용한다. 예를 들어 expression.setValue(Object bean, Object value)를 실행하기 위해 SpEL이 Short를 Long으로 강제해야 할 때 core.convert 시스템이 강제한다.

웹 어플리케이션이나 데스크톱 어플리케이션같은 전형적인 클라이언트 환경에서의 타입변환 요구사항을 생각해 보자. 이러한 환경에서는 보통 String을 클라이언트의 포스트백(postback) 과정을 지원하도록 변환하고 뷰 렌더링 과정을 위해 다시 String로 변환한다. 또한 때로는 문자열 값을 로컬라이징할 필요가 있다. 더 일반적인 core.convert Converter SPI는 포매팅같은 요구사항을 직접 다루지 않는다. 이러한 것들을 직접 다루기 위해 스프링 3는 PropertyEditor 대신 클라이언트 환경에서 사용할 수 있는 간단하고 신뢰할 수 있으며 편리한 Formatter SPI를 도입했다.

보통 범용적인 타입 변환 로직을 구현할 때 Converter SPI를 사용하는데 java.util.Date와 java.lang.Long 간에 변환을 하는 경우이다. 웹 어플리케이션같은 클라이언트 환경에서 작업하고 로컬라이징된 필드값을 파싱해서 출력해야 할 때 Formatter SPI를 사용해라. ConversionService는 두 SPI에 대한 일관된 타입변환 API를 제공한다.

6.6.1 Formatter SPI
필드 포매팅 로직을 구현하는 Formatter SPI는 간단하면서도 강타입이다.


1
2
3
4
5
6
Java

package org.springframework.format;

public interface Formatter<T> extends Printer<T>, Parser<T> {
}

Formatter는 Printer와 Parser 인터페이스를 상속받는다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Java

public interface Printer<T> {
  String print(T fieldValue, Locale locale);
}


Java

import java.text.ParseException;

public interface Parser<T> {
  T parse(String clientValue, Locale locale) throws ParseException;
}

위의 Formatter 인터페이스를 구현해서 자신만의 Formatter를 만들 수 있다. 파라미터 T는 포매팅할 객체의 타입으로 java.util.Date등이 될 수 있다. T의 인스턴스를 클라이언트 로케일(locale)로 출력하는 print()를 구현한다. 클라이언트 로케일이 반환한 포매팅된 표현에서 T의 인스턴스를 파싱하는 parse()를 구현해라. 작성한 Formatter가 파싱에 실패하면 ParseException나 IllegalArgumentException를 던져야 한다. Formatter가 쓰레드세이프하게 구현되도록 신경써라.

여러가지 포매터 구현체는 편리하게 format 하위패키지 아래 있다. number는 java.text.NumberFormat를 사용해서 java.lang.Number 객체를 포매팅하는 NumberFormatter, CurrencyFormatter, PercentFormatter를 제공한다. datetime 패키지는 java.util.Date 객체를 java.text.DateFormat로 포매팅하는 DateFormatter를 제공한다. datetime.joda 패키지는 Joda 시간 라이브러리에 기반해서 포괄적인 datetime 포매팅을 지원한다. Formatter 구현체의 예제로 DateFormatter를 보자.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
Java

package org.springframework.format.datetime;

public final class DateFormatter implements Formatter<Date> {

  private String pattern;

  public DateFormatter(String pattern) {
    this.pattern = pattern;
  }

  public String print(Date date, Locale locale) {
    if (date == null) {
      return "";
    }
    return getDateFormat(locale).format(date);
  }

  public Date parse(String formatted, Locale locale) throws ParseException {
    if (formatted.length() == 0) {
      return null;
    }
    return getDateFormat(locale).parse(formatted);
  }

  protected DateFormat getDateFormat(Locale locale) {
    DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);
    dateFormat.setLenient(false);
    return dateFormat;
  }

}

스프링 개발팀은 커뮤니티가 포매터를 추가하는 것을 환영하고 있다. 포매터에 공헌하려면 http://jira.springframework.org를 봐라.

6.6.2 어노테이션 기반의 포매팅
다음과 같이 필드 타입이나 어노테이션으로 필드 포매팅을 설정할 수 있다. 포매터에 어노테이션을 바인딩하려면 AnnotationFormatterFactory를 구현해라.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
Java

package org.springframework.format;

public interface AnnotationFormatterFactory<A extends Annotation> {

  Set<Class<?>> getFieldTypes();

  Printer<?> getPrinter(A annotation, Class<?> fieldType);

  Parser<?> getParser(A annotation, Class<?> fieldType);

}

파라미터 A는 org.springframework.format.annotation.DateTimeFormat같은 포매팅 로직과 연결될 annotationType 필드이다. getFieldTypes()는 어노테이션이 사용된 필드의 타입을 반환한다. getPrinter()는 어노테이션이 붙은 필드의 값을 출력하는 Printer를 반환한다. getParser()는 어노테이션이 붙은 필트의 clientValue를 파싱하는 Parser를 반환한다.

아래의 AnnotationFormatterFactory 구현예제는 포매터에 NumberFormat 어노테이션을 붙혔다. 이 어노테이션은 숫자형식과 패틴을 지정하게 한다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Java

public final class NumberFormatAnnotationFormatterFactory
      implements AnnotationFormatterFactory<NumberFormat> {

  public Set<Class<?>> getFieldTypes() {
    return new HashSet<Class<?>>(asList(new Class<?>[] {
      Short.class, Integer.class, Long.class, Float.class,
      Double.class, BigDecimal.class, BigInteger.class }));
  }

  public Printer<Number> getPrinter(NumberFormat annotation, Class<?> fieldType) {
    return configureFormatterFrom(annotation, fieldType);
  }

  public Parser<Number> getParser(NumberFormat annotation, Class<?> fieldType) {
    return configureFormatterFrom(annotation, fieldType);
  }

  private Formatter<Number> configureFormatterFrom(NumberFormat annotation,
                                                     Class<?> fieldType) {
    if (!annotation.pattern().isEmpty()) {
      return new NumberFormatter(annotation.pattern());
    } else {
      Style style = annotation.style();
      if (style == Style.PERCENT) {
        return new PercentFormatter();
      } else if (style == Style.CURRENCY) {
        return new CurrencyFormatter();
      } else {
        return new NumberFormatter();
      }
    }
  }
}

필드에 @NumberFormat 어노테이션을 붙혀서 포매팅을 실행한다.

1
2
3
4
5
6
7
8
Java

public class MyModel {

  @NumberFormat(style=Style.CURRENCY)
  private BigDecimal decimal;

}

6.6.2.1 포맷 어노테이션 API
포맷 어노테이션 API는 org.springframework.format.annotation 패키지에 있다. java.lang.Number 필드를 포매팅하려면 @NumberFormat를 사용하고 java.util.Date, java.util.Calendar, java.util.Long, Joda Time 필드를 포매팅하려면 @DateTimeFormat를 사용해라.

아래의 예제는 java.util.Date를 ISO Date (yyyy-MM-dd)로 포매팅하려고 @DateTimeFormat를 사용한다.


1
2
3
4
5
6
7
8
Java

public class MyModel {

  @DateTimeFormat(iso=ISO.DATE)
  private Date date;

}

6.6.3 FormatterRegistry SPI
FormatterRegistry 는 포매터와 컨버터를 등록하는 SPI다. FormattingConversionService는 대부분의 환경에 적합한 FormatterRegistry의 구현체이다. 이 구현체는 FormattingConversionServiceFactoryBean를 사용하는 스프링 빈처럼 프로그래밍적으로나 선언적으로 설정할 수 있다. 이 구현체가 ConversionService도 구현했기 때문에 스프링의 DataBinder와 스프링 표현언어(SpEL)를 사용해서 직접설정할 수도 있다. 아래의 FormatterRegistry SPI를 보자.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Java

package org.springframework.format;

public interface FormatterRegistry extends ConverterRegistry {

  void addFormatterForFieldType(Class<?> fieldType, Printer<?> printer, Parser<?> parser);

  void addFormatterForFieldType(Class<?> fieldType, Formatter<?> formatter);

  void addFormatterForFieldType(Formatter<?> formatter);

  void addFormatterForAnnotation(AnnotationFormatterFactory<?, ?> factory);

}

위에서 보았듯이 Formatter는 fieldType이나 어노테이션으로 등록할 수 있다.

FormatterRegistry SPI는 여러 컨트롤러에서 중복된 설정을 하는 대신에 중앙에 포매팅 규칙을 설정할 수 있다. 예를 들어 모든 Date 필드를 특정 방법으로 포매팅하거나 특정 어노테이션을 가진 필드를 특정 방법으로 포매팅하는 것을 강제할 수 있다. 공유된 FormatterRegistry로 이러한 규칙을 한번만 정의하고 포매팅이 필요한 곳마다 적용한다.

6.6.4 FormatterRegistrar SPI
FormatterRegistrar는 FormatterRegistry를 통해 포매터와 컨버터를 등록하는 SPI다.


1
2
3
4
5
6
7
8
9
Java

package org.springframework.format;

public interface FormatterRegistrar {

  void registerFormatters(FormatterRegistry registry);

}

Date 포매팅처럼 주어진 포매팅 분류에 따라 관련된 여러가지 컨버터와 포매터를 등록할 때 FormatterRegistrar가 유용하다. 선언적인 등록이 충분하지 않을 때도 유용하다. 예를 들어 포매터가 포매터의 <T>와는 다른 특정 필드 타입하에 색인되어야 하거나 Printer/Parser 쌍을 등록하는 경우이다. 다음 섹션에서는 컨터버와 포매터 등록에 대해서 더 자세히 얘기한다.

6.6.5 Spring MVC에서의 포매팅 설정
스 프링 MVC 어플리케이션에서 MVC 네임스페이스의 annotation-driven 요소의 속성으로 커스텀 ConversionService 인스턴스를 명시적으로 설정할 수 있다. 컨트롤러 모델 바인딩을 하면서 타입변환이 필요할 때마다 이 ConversionService를 사용한다. 명시적으로 설정하지 않은 경우 스프링 MVC는 숫자나 날짜같은 일반적인 타입에 대한 기본 포매터와 컨버터를 자동으로 등록할 것이다.

기본 포매팅 룰을 사용하는데 스프링 MVC 설정 XML에서 어떤 커스턴 설정도 필요없다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <mvc:annotation-driven/>

</beans>

이 한줄의 설정으로 @NumberFormat와 @DateTimeFormat 어노테이션을 포함해서 숫자와 날짜타임에 대한 기본 포매터를 설정할 수 있다. 클래스패스에 Joda Time 라이브러리가 있다면 Joda 타임 포매팅 라이브러리에 대한 완전한 지원을 할 수 있다.

커스텀 포매터와 컨버터가 등록된 ConversionService 인스턴스를 주입하려면 conversion-service 속성을 설정한 뒤 FormattingConversionServiceFactoryBean의 프로퍼티로 커스텀 컨버터나 포매터, FormatterRegistrar를 지정해라.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
    http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <mvc:annotation-driven conversion-service="conversionService"/>

  <bean id="conversionService"
      class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
      <set>
        <bean class="org.example.MyConverter"/>
      </set>
    </property>
    <property name="formatters">
      <set>
        <bean class="org.example.MyFormatter"/>
        <bean class="org.example.MyAnnotationFormatterFactory"/>
      </set>
    </property>
    <property name="formatterRegistrars">
      <set>
        <bean class="org.example.MyFormatterRegistrar"/>
      </set>
    </property>
  </bean>

</beans>

Note
FormatterRegistrar 사용에 대한 자세한 내용은 Section 6.6.4, “FormatterRegistrar SPI” 와 FormattingConversionServiceFactoryBean를 봐라.

6.7 Spring 3 유효성 검사(Validation)
스 프링 3에서는 유효성검사에 대한 지원이 여러 모로 강화되었다. 우선 JSR-303 Bean Validation API를 이제 완전히 지원한다. 두번째로 프로그래밍적으로 사용할 때 스프링의 DataBinder는 객체에 대한 바인딩 뿐만 아니라 객체의 유효성검사도 할 수 있다. 세번째로 스프링 MVC는 @Controller 입력에 대한 유효성 검사를 선언적으로 할 수 있다.

6.7.1 JSR-303 Bean Validation API의 개요
JSR- 303는 자바플랫폼의 유효성 검사 제약사항 선언과 메타데이터를 표준화한다. JSR-303 API를 사용해서 선언적인 유효성 제약사항으로 도에인 모델 프로퍼티에 어노테이션을 붙히고 런타임시에 이를 강제할 수 있다. 사용할 만한 다수의 내장 제약사항이 존재한다. 물론 자신만의 커스텀 제약사항도 정의할 수 있다.

설명을 위해 2개의 프로퍼티를 가진 간단한 PersonForm 모델을 생각해 보자.


1
2
3
4
5
6
Java

public class PersonForm {
  private String name;
  private int age;
}

JSR-303으로 이러한 프로퍼티에 대한 유효성 검사 제약사항을 선언적으로 정의할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
Java

public class PersonForm {

  @NotNull
  @Size(max=64)
  private String name;

  @Min(0)
  private int age;

}

JSR-303 Validator가 이 클래스의 인스턴스를 검사할 때 이러한 제약사항을 강제할 것이다.

JSR-303에 대한 일반적인 내용은 Bean Validation Specification를 봐라. 기본 레퍼런스 구현체의 특정 능력에 대한 내용은 Hibernate Validator 문서를 봐라. JSR-303 구현체를 어떻게 스프링 빈으로 설정하는지 알고 싶으면 계속 읽어봐라.

6.7.2 Bean Validation 구현체 설정
스 프링은 JSR-303 Bean Validation API를 완전히 지원한다. 이는 JSR-303 구현체를 스프링 빈으로 편리하게 설정하도록 하는 것도 포함한다. 또한 어플리케이션에서 유효성검사가 필요할 때마다 javax.validation.ValidatorFactory나 javax.validation.Validator를 주입할 수 있다.

기본 JSR-303 Validator를 스프링 빈으로 설정하려면 LocalValidatorFactoryBean를 사용해라.


1
2
3
Xml

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>

위의 기본 설정은 JSR-303의 기본 부트스트랩 메카니즘을 사용해서 JSR-303을 초기화한다. Hibernate Validator같은 JSR-303 프로바이더는 클래스패스에 존재해야 하고 자동적으로 탐지될 것이다.

6.7.2.1 Validator 주입
LocalValidatorFactoryBean 는 org.springframework.validation.Validator뿐만 아니라 javax.validation.ValidatorFactory와 javax.validation.Validator를 모두 구현한다. 이러한 인터페이스에 대한 참조를 유효성검사 로직을 실행해야하는 빈에 주입할 것이다.

JSR-303 API를 직접 사용하는 걸 좋아한다면 javax.validation.Validator에 대한 참조를 주입해라.


1
2
3
4
5
6
7
8
9
Java

import javax.validation.Validator;

@Service
public class MyService {

  @Autowired
  private Validator validator;

빈(bean)이 Spring Validation API를 필요로 한다면 org.springframework.validation.Validator에 대한 참조를 주입해라.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Java

import org.springframework.validation.Validator;

@Service
public class MyService {

  @Autowired
  private Validator validator;

}

6.7.2.2 커스텀 제약사항(Constraints) 설정
각 JSR-303 유효성검사 제약사항은 두 부분으로 구성되어 있다. 첫째, 제약사항과 설정가능한 제약사항의 프로퍼티를 설정하는 @Constraint. 두번째는 제약사항의 동작을 구현하는 javax.validation.ConstraintValidator 인터페이스의 구현체이다. 선언과 구현체의 연결을 위해 각 @Constraint 어노테이션은 대응되는 ValidationConstraint 구현체를 참조한다. 런타임시에 ConstraintValidatorFactory는 제약사항 어노테이션이 도메인 모델을 만났을 때 참조된 구현체를 인스턴스화한다.

기본적으로 LocalValidatorFactoryBean는 스프링이 ConstraintValidator 인스턴스를 생성하려고 사용하는 SpringConstraintValidatorFactory를 설정한다. 이는 다른 스프링 빈처럼 의존성 주입의 이점을 가진 커스텀 ConstraintValidator를 사용할 수 있다.

다음은 의존성주입을 위해 스프링을 사용하는 관련 ConstraintValidator 구현체가는 붙은 커스텀 @Constraint 선언의 예제이다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
Java

@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}


Java

import javax.validation.ConstraintValidator;

public class MyConstraintValidator implements ConstraintValidator {

  @Autowired;
  private Foo aDependency;

  ...
}

여기서 보듯이 ConstraintValidator 구현체는 다른 스프링 빈처럼 @Autowired로 의존성을 가진다.

6.7.2.3 추가적인 설정 옵션
대 부분의 경우에 기본 LocalValidatorFactoryBean 설정으로도 충분하다. 메시지 삽입부터 탐색 처리(traversal resolution)까지 다양한 JSR-303 생성에 대한 다수의 설정 옵션이 있다. 이러한 옵션에 대한 자세한 내용은 LocalValidatorFactoryBean의 JavaDoc을 봐라.

6.7.3 DataBinder 설정
스 프링 3부터 DataBinder 인스턴스는 Validator와 함께 설정할 수 있다. 일단 설정되면 binder.validate() 호출에 의해서 Validator가 실행된다. 유효성 검사 오류는 자동적으로 바인더의 BindingResult에 추가된다.

프로그래밍적으로 DataBinder를 사용하는 경우 타겟 객체에 바인딩한 후 유효성 검사 로직을 실행하려고 DataBinder를 사용한다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Java

Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator());

// 타겟 객체에 바인딩
binder.bind(propertyValues);

// 타겟객체의 유효성 검사
binder.validate();

// 유효성검사 오류를 포함한 BindingResult 획득
BindingResult results = binder.getBindingResult();

6.7.4 Spring MVC 3 Validation
스프링 3부터 스프링 MVC는 @Controller의 입력을 자동으로 유효성감사할 수 있다. 이전 버전에서는 개발자가 수동으로 유효성검사 로직을 실행해야 했다.

6.7.4.1 @Controller 입력의 유효성 검사 실행
입력 아규먼트에 간단히 @Valid 어노테이션을 붙혀서 @Controller 입력에 대한 유효성검사를 실행한다.


1
2
3
4
5
6
7
Java

@Controller
public class MyController {

  @RequestMapping("/foo", method=RequestMethod.POST)
  public void processFoo(@Valid Foo foo) { /* ... */ }

적절한 Validator가 설정되었다면 Spring MVC 바인딩한 후 @Valid 객체의 유효성을 검사한다.


Note
@Valid 어노테이션은 표준 JSR-303 Bean Validation API의 일부이고 스프링에 한정된 것은 아니다.

6.7.4.2 Spring MVC가 사용하는 Validator 설정
@Valid 메서드 아규먼트가 있을때 호출되는 Validator 인스턴스는 2가지 방법으로 설정할 수 있다. 첫번째 방법은 @Controller의 @InitBinder 콜백내에서 binder.setValidator(Validator)를 호출하는 것이다. 이 방법으로 @Controller마다 Validator 인스턴스를 설정할 수 있다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
Java

@Controller
public class MyController {

  @InitBinder
  protected void initBinder(WebDataBinder binder) {
   binder.setValidator(new FooValidator());
  }

  @RequestMapping("/foo", method=RequestMethod.POST)
  public void processFoo(@Valid Foo foo) { ... }

}

두번째 방법은 전역 WebBindingInitializer에서 setValidator(Validator)를 호출하는 것이다. 이 방법으로 모든 @Controllers에 걸쳐서 Validator 인스턴스를 설정할 수 있다. 이는 Spring MVC 네임스페이스로 쉽게 설정할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <mvc:annotation-driven validator="globalValidator"/>

</beans>

6.7.4.3 Spring MVC가 사용하는 JSR-303 Validator 설정
JSR-303에서 단일 javax.validation.Validator 인스턴스는 보통 유효성검사 제약사항을 선언한 모든 모델 객체의 유효성을 검사한다. 스프링 MVC에 JSR-303에 기반한 Validator를 설정하려면 Hibernate Validator같은 JSR-303 Provider를 클래스패스에 추가한다. 스프링 MVC는 자동으로 이 프로바이더를 탐지해서 모든 컨트롤러에 걸쳐서 JSR-303 지원을 활성화할 것이다.

JSR-303 지원을 활성화하는데 필요한 스프링 MVC 설정은 다음과 같다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
Xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="
   http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
   http://www.springframework.org/schema/mvc
   http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

  <!-- JSR-303 support will be detected on classpath and enabled automatically -->
  <mvc:annotation-driven/>

</beans>

이러한 최소의 설정으로 @Valid @Controller 입력을 만났을 때마다 JSR-303 프로바이더가 유효성을 검사한다. 다음으로 JSR-303은 입력에 대해 설정된 제약사항을 강제할 것이다. 모든 ConstraintViolation은 표준 스프링 MVC 폼태그로 랜더링할 수 있는 오류로 BindingResult에 노출된다.