티스토리 툴바

KSUG 1회 세미나이기도 한 이프릴 세미나 첫 발표는 "다중 레이어 환경에서 Spring을 활용한 통합 테스트 및 단위 테스트 방안"이다. 당시 국내 스프링 사용자에게 거의 알려지지 않은 보석 같은 내용을 일주일 동안 연습해서 시연하던 기억이 생생하다. 월간 마소에 일민 형이 기고한 글을 줄거리로 한 라이브 코딩이었다.

사용자 삽입 이미지

사진 출처: 이프릴(Epril) 스프링 세미나 풍경

그간 스프링의 테스트 지원 기능은 Java 5 프로그래밍 요소에 맞춰 우아하게 변모하여 Spring TestContext Framework로 발전했다.

이와 관련한 책 읽기 모임 의견을 들어보자. 찬욱군은 TestContext를 학습하면서 JUnit 3.8과 JUnit 4.x 호환성을 지키는 부분에 놀랐다고 한다. 나는 주입을 위해 굳이 생성자나 수정자가 필요하지도 않게 배려한 부분에서 감동했다. :)

테스트 코드에 의한 DI
책을 따라 실습해보면 무리 없이 스프링 테스트 컨택스트를 배울 수 있다. 다만, @DirtiesContext 내용이 정확히 와 닿지 않았다. 이런 경우라면 다음 절에 소개하는 학습 테스트를 만들어 명확히 할 수 있다. 여러 개의 테스트 클래스를 만들고 한 쪽에 정적 변수로 ApplicationContext 개체를 참조할 수 있게 한다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="/testcontext/applicationContext.xml")
public class AaaTest {
   
    static ApplicationContext firstContext;

그리고 테스트 클래스에서 정적 변수를 한 번은 초기화하게 한다.

    @Before
    public void setUp(){
        if(AaaTest.firstContext == null) AaaTest.firstContext = applicationContext;
    }

마지막으로 정적 변수와 멤버 변수인 applicationContext가 가리키는 개체가 같은지 비교하는 테스트를 여러 개 만든다. @DirtiesContext를 클래스에 붙였다가 메소드에 붙여본다.

    @Test
    public void test1(){
        assertEquals(AaaTest.firstContext, applicationContext);
    }
   
    @DirtiesContext
    @Test
    public void test2(){
        assertEquals(AaaTest.firstContext, applicationContext);
    }

@DirtiesContext를 클래스에 붙이면 해당 클래스가 끝날 때 애플리케이션 컨텍스트가 새로 만들어진다. 메소드에 붙이면 해당 메소드가 끝나면 새로 만들어진다.

저자의 꼼꼼함을 들여다볼 수 있긴 했으나, 찬욱군은 현장에서 @DirtiesContext가 필요한 경우에 대해 아직 감이 없다고 한다.

컨테이너 없는 DI 테스트

UserDaoTest는 사실 UserDao 코드가 DAO로서 DB에 정보를 잘 등록하고 잘 가져오는지만 확인하면 된다. 스프링 컨테이너에서 UserDao가 동작함을 확인하는 일은 UserDaoTest의기본적인 관심사가 아니다. DaoFactory를 만들어 의존관계 설정 책임을 분리하기 직전에 테스트 코드에서 DI 작업을 직접 했던 것을 기억할지 모르겠다. 바로 그 방법을 사용해서 UserDao가 동작하게 만들고 테스트할 수 있다.

2장까지 내용을 충분히 이해했다면 쉽게 읽고 넘어갈 내용이지만, 사실 관심사 분리(SoC) 훈련이 없다면 이해하지 못할 내용이 아닐까 싶다. 혹시 발췌한 내용이 이해가 가지 않거나 갑자기 왜 이런 설명을 하는지 이해가 안 간다면 안타깝지만 1장을 다시 읽어야 한다. :)

DI를 이용한 테스트 방법 선택
다양한 방법을 소개하고 마지막에 선택 기준을 제시한다. 1번은 역시 스프링 컨테이너조차 없는 테스트다. 앞서 설명한 고립성과 시간 절약은 스프링 컨테이너에도 그대로 해당한다. 스프링 컨테이너를 이용하는 기준은 무엇인가? 여러 개체와 복잡한 의존관계를 갖는 개체를 테스트할 경우다. 이 경우는 테스트 설정을 따로 만드는 방법이 좋다. 세 번째는 예외적인 의존관계를 강제로 구성할 경우다. 이때는 앞서 학습한 @DirtiesContext가 유용하다.

§ 2.5 학습 테스트로 배우는 스프링
작년인가 월간 마소에 JUnit을 이용한 코드 개선 과정 녹화라는 글을 기고한 일이 있다. 개발 후 운영자도 내막을 잘 모르는 레거시 코드를 학습하는 과정과 이를 공유하는 수단으로 테스트를 사용한 경험담이다. 저자가 열거한 학습 테스트 다섯 가지 장점을 그 경험에 대입해보니 그대로 들어맞는다. 학습 테스트는 과정에서 배우는 바도 매우 크지만, 결과를 보존하면 문서로는 전달하기 어려운 생생한 재현을 보장한다. 특히나 프레임워크나 제품의 주요 기능 혹은 API 쓰임새를 포괄하는 테스트를 만들어 둔다면 마치 TCK(Technology Compatibility Kit)처럼 훌륭한 호환성 검증 도구 역할을 할 수 있다.

설정

트랙백

댓글

* 책 읽기 토론 내용을 반영해 수정 (2010.10.30) <- 최초 작성(2010.9.30)

157쪽에서 수정 후에는 성공 메시지가 "조회 테스트 성공"으로 바꾸어야 하는데 출판사 정오표에는 빠진 오류인 듯하다. 159쪽 하단에 JUnit 필수 조건에도 void 가 빠져 있다. 170쪽에 내용이 나오는 내용인지라 저자가 실수로 빠뜨린 듯하다. 저자는 스프링 3.0에서 처음 등장한 설정 방법부터 소개한 것처럼 assertEquals() 메소드보다 assertThat() 메소드부터 소개한다. assertThat은 예전에 만든 교육 자료가 있어 일부를 공개한다.


Joe Walnes의 글은 Flexible JUnit assertions with assertThat()이다. assertThat 자체는 JUnit에 들어갔지만, 책에서 사용하는 Matcher는 hamrest 라이브러리에 있다. 책 읽기 모임에서 나온 의견을 덧붙여 보자. JUnit을 충분히 써본 찬욱군은 굳이 assertThat을 사용하는 이유를 모르겠다고 한다. 이에 대해 용권씨는 Scala 학습 전에는 자신도 몰랐으나 이제는 DSL로 대변하는 가독성 있는 스타일에 대해 이해가 가며, assertThat도 같은 맥락으로 이해한다고 했다. 내 생각엔 assertThat 자체는 영어문화권이 아닌 우리에게 큰 의미는 없다. 다만, Matcher는 (클래스 수준 이하) 단위 테스트를 돕는 훌륭한 개념이기 때문에 은근 슬쩍 스프링 학습과정에서 배웠으면 하는 저자의 노파심이 아닐까 싶다. 찬욱군 의견처럼 161쪽 리스트 2-5는 assertEqual이 차라리 낫다. :)


JUnit에 hamcrest가 포함되어 있긴 하지만, 테스트 주도 개발 TDD 실천법과 도구에 따르면 최신 버전(1.2)은 직접 내려받아야 한다. hamcrest에 대한 자세한 내용은 테스트 주도 개발 TDD 실천법과 도구에서 배울 수 있다. 134쪽부터 약 15쪽 정도 분량으로 hamcrest 기초부터 확장 방법까지 설명하고 있다.

테스트 주도 개발 - 10점
채수원 지음/한빛미디어


205~206쪽을 보면 종전 사용법까지 포함한 여러 가지 확인 코드 작성 방식을 보여준다. 저자는 더 나아가 자신의 블로그를 통해서 JUnit assert 매쉬업이라는 최신 기법까지 소개하고 있다.

개발자를 위한 테스팅 프레임워크 JUnit
저자는 다시 한번 테스트를 강조한다.

다시 말하지만 테스트 없이는 스프링도 의미 없다.

역시 지나치다 싶을 정도로 초강수를 둔다. 하지만, 단위 테스트가 주는 이점(품질 향상, 빠른 개선 주기 지원)을 공감하지 못하는 개발자에게 이 정도 위협(?)이 먹힌다면 의미는 있다. 필자는 다른 회사가 개발을 맡는 2번의 프로젝트에서 DAO 단위 테스트만 의무화했던 경험이 있는데 모두 예상치를 웃도는 효과를 얻었다. '우리도 한번 해보자!'라고 하시는 분은 저렴한 방법으로는 테스트 주도 개발 TDD 실천법과 도구 학습이 있고, 비용이 들어가는 방법으로는 필자에게 컨설팅 요구를 하실 수 있다. :)

동일한 결과를 보장하는 테스트

따라서 테스트 후에 USER 테이블을 지워주는 것도 좋지만, 그보다는 테스트하기 전에 테스트 실행에 문제가 되지 않는 상태를 만들어주는 편이 더 나을 것이다.

혼동하기 쉬운 내용을 잘 지적하는 내용이다. 외부 요인이나 실행 순서가 테스트에 영향을 미치지 않도록 실험실 꾸미듯 단위 테스트를 만들어야 한다.

주의해야 할 점은 두 개의 테스트가 어떤 순서로 실행될지는 알 수 없다는 것이다. JUnit은 특정한 테스트 메소드의 실행 순서를 보장해주지 않는다. 테스트의 결과가 테스트 실행 순서에 영향을 받는다면 테스트를 잘못 만든 것이다. 예를 들어 addAndGet() 메소드에서 등록한 사용자 정보를 count() 테스트에서 활용하는 식으로 테스트를 만들면 안 된다. 모든 테스트는 실행 순서에 상관없이 독립적으로 항상 동일한 결과를 낼 수 있도록 해야 한다.


포괄적인 테스트
토스 177쪽을 보면, 스프링의 창시자인 로드 존슨이 '항상 네거티브 테스트를 먼저 만들라'라고 조언했다고 하는데 정말 그럴까?  Expert One-on-One J2EE Development without EJB 430쪽에 Negative Tests라는 내용이 나온다. '항상 먼저 만들라'라고 한 내용은 찾을 수 없지만, 바람직한 작동을 위한 테스트만큼이나 비정상적일 때에 대한 테스트도 잊지 말 것을 강조하고 있다. 영어라 접근에 제약은 있지만, Expert One-on-One J2EE Development without EJB 14장은 J2EE/Java EE 영역에 있어서만큼은 가장 얇으면서 풍부한 내용을 담은 주옥같은 글이니 꼭 읽어보길 권한다. 사실 많은 내용이 토스에 녹아 있긴 하다.

책 읽기 모임에서 용권씨가 막장(?) 사례를 말해줬다. 이를 테면 assertTrue(true)와 같은 코드로 단위 테스트를 한 경우도 있단다. ㅡㅡ;

반면에 찬욱군은 외부 솔루션이나 고객 사이트 환경을 모르고 대답해주는 이가 없어서 대충 테스트 했던 과거를 회계했다.

테스트 코드 개선
테스트 순서나 외부 요인에 영향을 받지 않는 고립 테스트의 중요성은 여러 차례 이야기했다. JUnit은 이를 위해 테스트마다 별도 개체를 생성한다. 토스 2장에서는 실습과 함께 체득하기 때문에 효과적으로 익힐수 있다.

픽스처
테스트 픽스처(Test fixture)에 대한 위키피디아 정의를 옮겨본다.

Test fixture refers to the fixed state used as a baseline for running tests in software testing. The purpose of a test fixture is to ensure that there is a well known and fixed environment in which tests are run so that results are repeatable. Some people call this the test context.


설정

트랙백

댓글

* 책 읽기 토론 내용을 반영해 수정 (2010.10.30) <- 최초 작성(2010.9.29)

아래 발췌한 도입부 내용은 테스트에 대한 강조가 지나쳐 마치 스프링을 볼모로 독자를 위협하는 듯한 인상을 받는다.

스프링으로 개발을 하면서 테스트를 만들지 않는다면 이는 스프링이 지닌 가치의 절반을 포기하는 셈이다. 스프링 개발자라면 테스트 작성 방법과 이를 효과적으로 개발에 활용하는 전략을 알아야 하며, 이를 실전에 적용할 수 있어야 한다.

스프링 프레임워크 자체는 테스트를 강제하지 않는다. 그럼에도 저자가 2장 전반에 걸쳐 무리다 싶을 정도로 강조하는 이유는 무엇일까? 추측건대 테스트를 거의 하지 않는 개발 풍토 탓이 아닐까? 2005년부터 현재까지 참여한 9개 프로젝트 가운데 단위 테스트 작성에 성공(?)한 경우는 5회이고, 실패한 경우는 4회다. 다른 이유를 배제하면 단위 테스트에 성공한 다섯 번은 모두 납기 내에 시스템을 오픈했다. 단위 테스트 작성을 도입하지 못한 4번 중 3개의 프로젝트는 필자가 조기 철수하는 프로젝트여서 결말은 모르지만 무리한 야근이 있었다는 점은 확인할 수 있었다. 그리고 필자의 참여 비중(주 1회)이 낮아 어찌할 수 없이 실패를 지켜봤던 1번은 6개월가량 오픈이 늦어졌다. 자동화 테스트와 회귀 테스트를 충족하는 단위 테스트의 효과는 분명한데 실전에 도입하기란 만만치 않다. 필자가 성공한 5번의 프로젝트 중에 3번은 우리 팀만으로 개발한 경우다. 우리 팀에서도 단위 테스트를 한 번도 작성하지 않았던 개발자가 있었지만, 짝 프로그래밍 형태로 일주일만 가르쳐주면 무리 없이 테스트를 작성했다. 문제는 소속이 다른 여러 조직에서 개발하는 경우다. 필자는 항상 단위 테스트를 주장하지만, 개발이 끝날 때까지 참여하는 경우만 힘을 쓸 수 있었다. 필자를 대신하여 테스트를 유도하고, 개발자가 막힐 때 방법을 알려줄 사람이 없기 때문이다. 성공한 두 차례중 한 번은 외국에서 훈련 받은 최고수준의 프로젝트 관리 진이 포진한 경우였다. 그렇지 않은 한 차례는 필자가 속한 팀이 프로젝트 관리 조직을 장기간 계몽(?)했다. 사실 투쟁의 역사이기도 했다. 그리고 실무적으로도 1,000회 정도의 코드 인스펙션을 수행했다. 우리 팀 개발자는 '차라리 내가 짜는 편이 빠르겠다'는 불평을 수없이 내뱉었다. 이런 사회적 배경을 고려하면 테스트는 아무리 강조해도 지나치지 않다.

토론 모임에서는 '스프링을 통해 처음으로 자동화 테스트를 경험했다'는 사람이 많았다. 소수지만 모인 사람만 놓고 보면 압도적인 비중이었다. 한편으로는 스프링이 현실에서 테스트를 적합하게 해낸 사례기도 하다.

작은 단위의 테스트

직접 관계는 없지만, JSP 모델1 구조에서 화면 단위로 테스트하던 모델2 MVC 구현일텐데. 그 부분이 아니라 아이들이 학교와 와야 의미가 있겠죠.

지금까지 UserDaoTest를 수행할 때 매번 USER 테이블의 내용을 비우고 테스트를 진행했다. 이렇게 사용할 DB의 상태를 테스트가 관장하고 있다면 이는 단위 테스트라고 해도 된다. 다만, DB의 상태가 매번 달라지고, 테스트를 위해 DB를 특정 상태로 만들어줄 수 없다면 그때는 UserDaoTest가 단위 테스트로서 가치가 없어진다. 그런 차원에서 통제할 수 없는 외부의 리소스에 의존하는 테스트는 단위 테스트가 아니라고 보기도 하는 것이다.

토스 151쪽 내용은 단위 테스트 경험자라면 누구나 고민해봤거나 고민했어야 할 내용을 잘 짚어낸 좋은 예다. 단위 테스트의 고립(isolated) 테스트 특성을 잘 설명한 내용이다. 필자는 2006년 단위 테스트의 "단위"라는 글을 쓸 즈음에 단위 테스트 개념을 이해하려고 여러 가지 시도를 한 바 있다. Mock을 이용한 테스트가 단위 테스트를 이해하는 데 큰 도움이 되었다. 국내 블로그 등에서 "단위"에 대한 고민을 찾을 수 없다는 점은 얼마나 단위 테스트를 안 하는지를 반증한다. 예전에 단위 테스트에 대해 고민했던 흔적을 남겨둔다.


저자는 작은 단위 테스트의 효과를 문제가 발생했을 때 찾을 수 있다고 설명한다. 프로젝트 전체를 놓고 생각하니 V 모델이 입자 크기와 겹쳐져서 떠올랐다. 프로젝트 초반에는 시스템을 규정하는 입자가 크고, V 모델 하부 구현단계에 들어서면 입자가 가장 작아졌다가 점차 테스트 입자가 커지는 그림이 머릿속에 그려졌다.

File:Systems Engineering Process II.svg
출처: 위키피디아

검증과 확인을 제공하는 V 모델의 효과를 극대화하는 방법은 무엇이 있을까? 수학적으로 증명할 수는 없지만, 빠른 피드백을 받고자 한다면 가장 작은 V 인스턴스(?)를 만드는 방법이다. 다시 말해서 작은 단위 테스트를 활용하는 방법이다. 필자가 켄트벡의 TDDBE를 읽고 가장 인상 깊었던 부분이 바로 작은 테스트를 통해 찾아가는 리듬인데, 앞서 사용한 표현에 따라 가장 적절한 V 인스턴스 크기라고 말할 수 있다. 린 소프트웨어 개발의 적용에서도 작은 테스트를 지지하는 경구를 제공한다.


하지만, 적절한 V 인스턴스 크기를 찾는 일은 매우 높은 밀도로 상당 기간 경험을 쌓았을 때 주어지는 선물이다. 볼링 게임으로 처음 TDD를 배우던 때를 회상하면 밥 삼촌이 카타에서 보여준 놀라운 칼질은 내공 차이를 명확히 보여준다.

저자는 단위 테스트에 대해서 개발자 테스트라는 다른 표현을 제시한다. 책에서 다루는 단위 테스트 작성자가 개발자임을 분명히 한다. 단위 테스트 수행자가 누구냐에 따라 테스트 목적이 달라지고, 프로젝트 갈등 구도도 달라진다. 하지만, 설사 제삼자 테스트 형태로 단위 테스트를 수행하는 이상적인 조직이 있다고 해도 개발자 스스로 단위 테스트를 해야 한다. 그렇지 않은 코드는 부실 코드(anemic code)라 불러 마땅하다.

자동수행 테스트 코드

이렇게 테스트는 자동으로 수행되도록 코드르 만들어지는 것이 중요하다. 어떤 개발자는 모든 클래는 스스로 자신을 테스트하는 main() 메소드를 갖고 있어야 한다고 주장하기도 한다. 굳이 모든 클래스의 main() 메소드에 테스트 코드가 들어가 있을 필요까지는 없겠지만, 어쨌든 테스트 자체가 사람의 수작업을 거치는 방법을 사용하기보다는 코드로 만들어져서 자동으로 수행될 수 있어야 한다는 건 매우 중요하다.

저자는 수치까지 예를 들며 자동화 테스트의 중요성을 설명한다. 사실 자동화 테스트 작성의 생소함 탓에 놓치기 쉬운 그러나 실로 엄청난 자동화 테스트의 위력이다. 프로젝트 전체를 놓고 보면 잘 만든 자동화 테스트가 모여 만들어낸 회귀 테스트 자산의 힘은 말로 설명하기 어렵다. 앞에 언급한 필자의 경험을 놓고 보면 프로젝트 성공의 핵심 열쇠 중 하나다.

작은 시간이라도 아끼라는 자동수행 테스트 저번에 깔린 교훈은 필자가 학교에서 C++을 배울 때 가장 먼저 마음에 새긴 원칙인 Principle of least privilege을 떠오르게 한다. 이른바 POLA 원칙은 변수의 가시성(scope) 맥락에서 배웠지만, 자원 사용에 대한 정책이나 보안에도 응용된다. 그런데 지금 생각해보니 프로젝트에 주어진 시간 자원에 적용해도 의미가 살아난다.

지속적인 개선과 점진적인 개발을 위한 테스트
다시 한번 V 모델을 떠올린다. 작은 단위 테스트가 쌓여 회귀 테스트 기반을 이루어 시스템 전반을 검증할 수 있는 토대를 만드는 양상은 실용적인 V 모델 적용의 전형적인 예다. 아쉽게도 많은 프로젝트에서는 V 모델의 맥락을 충분히 이해하지 못하고 높은 성숙도를 요하는 이론을 그대로 적용하려고 옥신각신하는 모습을 볼 수 있다. 진정 V 모델을 실현하고자 한다면 긴 호흡으로 계획하여 단장은 필수적인 단위 테스트부터 팀/조직에 보급하고 성숙도를 높아지면 더 큰 그림을 그리는 방법이 어떨까?

UserDaoTest의 문제점
옥에 티 수준이지만, 두 번째 문제점 제목은 실행 작업의 번거로움보다는 체계적인 테스트 실행의 어려움이 나을 듯하다. UserDaoTest를 수정한다고 실행 작업을 벗어나는 것은 아니다. 155쪽 내용에도 체계적인 테스트 실행과 결과 확인에 대해 이야기하고 있다.

설정

트랙백

댓글

부가기능 추가
부가기능 추가에 제격인 GoF 설계 패턴은 데코레이터(Decorator)다. 토스가 패턴 책은 아니니까 굳이 거론하지는 않지만, 124~125쪽 예가 바로 데코레이터 패턴으로 기능을 추가하는 내용이다. GoF 책 175~184쪽에 해당하며, 2006년에 간단히 요약한 일이 있다.

§ 1.8 XML을 이용한 설정
앞서 말한 바대로 토스 전개는 물 흐르듯 스프링을 소개하고 있다. 사용자 코드에 설정을 위한 최소한의 코드만 추가한다. 이 과정에서 자연스레 3.0의 새로운 설정방식부터 소개한다. 전통적인 설정방식은 오히려 나중에 소개하는 시간의 역순 흐름이 세련된 구성을 돋보이게 해준다.

XML 설정

<bean> 태그의 class 애트리뷰트에 지정하는 것은 자바 메소드에서 오브젝트를 만들 때 사용하는 클래스 이름이라는 점에 주의하자. 메소드의 리턴 타입을 class 애트리뷰트에 사용하지 않도록 하자.

131~132쪽에서 강조한 내용 역시 비대칭성을 내포한 XML 설정 특성을 이야기한다. 실수를 유발할 수 있는 비대칭성이 바로 DI를 통해 제공하는 마법이라는 점을 이해해야 한다. 마법은 이미 오래전 GoF에서도 거론하는 Dynamic Binding이다. 134쪽에서 지적한 주의사항도 비슷한 맥락에서 이해할 수 있다.

<property> 태그의 name과 ref는 그 의미가 다르므로 이름이 같더라도 어떤 차이가 있는지 구별할 수 있어야 한다. name 애트리뷰트는 DI에 사용할 수정자 메소드의 프로퍼티 이름이며, ref 애트리뷰트는 주입할 오브젝트를 정의한 빈의 ID다. 보통 프로퍼티 이름과 DI 되는 빈의 이름이 같은 경우가 많다.

아래와 같이 <property>태그의 두 속성값이 같다 해도 쓰임새는 전혀 다르다. <bean> 태그의 name 속성과 ref 속성값은 둘 다 실행시점에 의미가 있다. 다시 말해 Dynamic Binding 대상으로 코드를 바꾸지 않고 수정할 수 있다.

<property name="connectionMaker" ref="connectionMaker" />

반면에 <property> 태그의 name 속성은 특정 빈의 수정자 메소드 이름과 연계된다. 즉, 코드 내용과 변화 주기가 같다.

XML을 이용하는 애플리케이션 컨택스트
3.0에서 새로 추가한 GenericXmlApplicationContext(이하 GXAC)를 소개한다. GenericXmlApplicationContext는 사실상 ClassPathXmlApplicationContext(이하 CPXAC)나 FileSystemXmlApplicationContext를 대신하기 때문에 독자는 자연스럽게 권장하는 사용법을 배우는 셈이다. 토스는 꼼꼼하게도 그나마 ClassPathXmlApplicationContext가 필요한 경우까지 설명한다. 특정 클래스 위치를 기준으로 설정 파일을 찾을 경우다. 저자의 꼼꼼한 노력은 스프링의 빠른 개선 속도 탓에 아쉽게도 조만간 낡은 내용이 된다. 자바콘픽 개발자인 Chris Beams가 스스로 이슈(SPR-7530)를 올리고 수정한 내용을 반영(#3660)했다.

public GenericXmlApplicationContext(Class<?> relativeClass, String... resourceNames)

같은 기능을 하던 CPXAC 생성자는 기준 클래스가 뒤에 나왔지만, GXAC는 varargs를 쓰기 때문에 앞쪽에 나온다. 문자열이나 문자열 배열로 써야 했지만, varargs 채용으로 여러 개의 문자열도 가능해졌다. 곧 출시할 3.0.5 버전에 포함될 예정이다.

value 값의 자동 변환
value에 지정한 값을 자동 변환해주는 내용은 편의성과 신뢰성을 높이는 데 상당한 역할을 하지만 내공이 부족해서인지 충분히 감흥을 얻지 못하고 설명할 방법도 모르겠다.


더 읽어 보기
1장과 관련해서 더 읽어볼 만한 글 링크 모음


설정

트랙백

댓글

§ 1.6 싱글톤 레지스트리와 오브젝트 스코프
서버 프로그래밍에서 중요한 개념인 싱글톤과 스프링이 제공하는 싱글톤 레지스트리를 설명한다. 싱글톤 이해를 위해 필요한 오브젝트의 동일성과 동등성 설명이 나온다. 동등성이란 표현도 나쁘지 않지만, 동치(同値)라는 표현이 더 마음에 든다.

동치
수학논리학에서 동치(同値)란 두 문장이 논리적으로 같다는 것을 의미한다. 이것은 한 문장이 참이면 다른 한 문장도 참이고, 한 문장이 거짓이면 다른 문장도 거짓이 된다는 것을 뜻한다.

싱글톤 코드를 살펴보고 단점을 짚어본 후에 싱글톤 레지스트리(혹은 애플리케이션 레지스트리)로 바꾸는 흐름은 Expert One-On-One J2Ee Design and Development 139~141쪽과 같다. 싱글톤뿐 아니라 로드 존슨의 첫 번째 스프링 책의 4장 Design Techniques and Coding Standards for J2EE Projects는 주옥같은 내용을 닮고 있는데, 토스
1장에는 여기서 영감을 얻었음을 추측한 만한 내용이 많다. 영문을 읽을 여력이 있는 분은 토스 책을 읽은 후에 Expert One-On-One J2Ee Design and Development 4장도 일독하시길 권한다. 

§ 1.7 의존관계 주입(DI)
토스 115쪽 위쪽에 '사용에 대한 의존관계'란 어색한 표현이 있다. '사용 관계'라고 했으면 명확할 뻔했다. UML 창시자가 직접 쓴 UML 사용자 지침 88쪽을 보면, 의존관계를 쉽게 정의했다.

의존(dependency)은 사용 관계다. 예를 들어 파이프는 운반하는 물을 데우는 일을 히터에 의존한다.

115~119쪽으로 이어지는 내용은 설명하기 까다롭지만, 무척 중요한 내용이다 보니 UML을 동원해서 설명하고 있다. 내용을 이해하는 데에는 문제가 없지만 어색한 표현이 눈에 띈다. 집필 당시 일민 형이 UML에 대해 조언을 구했었는데, 당시는 도와줄 여력이 없었다. 돌아보니 조금 아쉽고 미안하네.

116쪽에 다시 '런타임 의존관계'란 표현이 나오는데 앞에서도 말했다시피 UML 문맥에서는 오류다. 개발/설계시점에서 정의한 관계에 의해 실행시점(runtime)에 링크가 만들어지기 때문에 의존관계란 표현을 쓰기 때문이다. 119는 표현 자체는 나쁘지 않지만, UML 도해라면 잘못된 표현이다. 어떻게 그러야 UML 도해 한 장으로 이를 표현할 수 있을지는 모르겠다. 코드 작성시점에 개체 사이에 존재하는 관계를 그린 그림은 다음과 같다. 토스에서는 '모델링 시점'이라고 했지만 '코드를 작성하는 시점'으로 이해해도 무방하다.


UserDao 클래스와 DConnectionMaker 클래스 사이에는 직접 관계가 없다는 점이 핵심이다. 관계가 없다는 의미는 DConnectionMaker 코드를 고려하지 않고, UserDao 코드를 작성할 수 있다는 의미기도 하다. 작성할 때는 그렇고, 실행시점에는 다음과 같은 개체도(Object diagram)로 나타낼 수 있다. 먼저 UserDao 객체 입장에서 그리면, ConnectionMaker 타입으로 인식하는 개체기 때문에 다음과 같이 그릴 수 있다.


반면에 실제 구체 클래스를 드러내도록 그리면 다음 그림과 같다. 자바가 제공하는 Dynamic Binding에 의해 같은 개체가 하나 여러 유형으로 표현될 수 있다. 이런 성질을 다형성이라고 한다.



의존관계 검색과 주입
1장 토론 모임에서 찬욱군이 '왜 의존관계 검색이 IoC인지 이해가 안되 강의 때 설명하면서도 어려움이 있었는데 토스를 읽고 수긍이 갔다'고 했다. 공감했다. 또, 토스의 의존관계 검색과 주입에 대한 설명 중에 가장 인상적인 내용은 아래 문장이다.

의존관계 검색 방식에서는 검색하는 오브젝트는 자신이 스프링의 빈일 필요가 없다는 점이다.

의존관계 검색 방식의 쓰임새에 대한 힌트를 주는 부분이다. 스프링 컨테이너의 통제 범위 밖에서 즉, 스프링 관리 대상이 아닌 개체가 관리 대상인 개체를 찾을 때는 의존관계 검색이 유용하다. 다만, 의존관계 검색이라는 표현이 어색하다. 검색 대상이 개체인데 관계를 검색하는 듯한 어감이다.

의존관계 주입의 응용
123쪽에서 기능 구현의 교환 예를 들기 위해 수정이 필요한 상황을 언급한다. 앞서 인용한 내용이 다시 떠올랐다.

변화의 성격이 다르다는 건 변화의 이유와 시기, 주기 등이 다르다는 뜻이다.

123에서 제시하는 대처법은 변화의 성격에 따라(concerns) 분리하여 다루기 위한 SoC 적용 과정이기도 하다. SoC 원칙을 실천하는 방안은 여러 가지가 있겠지만 우선 중복을 제거하는 '평면적' 방법과 인터페이스와 구현체를 분리하는 '계층적' 방법을 토스에서 배운다.


설정

트랙백

댓글

 § 1.5 스프링의 IoC

빈 팩토리라고 말할 때는 빈을 생성하고 관계를 설정하는 IoC의 기본 기능에 초점을 맞춘 것이고, 애플리케이션 컨텍스트라고 말할 때는 애플리케이션 전반에 걸쳐 모든 구성요소의 제어 작업을 담당하는 IoC 엔진이라는 의미가 좀 더 부각된다고 보면 된다.
토스 97쪽

명확하게 하기 위해서 Professional Java Development With The Spring Framework에서 빈 팩토리와 애플리케이션 컨텍스트 차이를 설명한 내용을 찾았다. 49쪽을 보면 애플리케이션 컨텍스트에만 있는 내용을 다음 네 가지 항목으로 정리했다.
  • General framework-oriented usage style
  • MessageSource support
  • Support for application and framework events
  • ResourceLoader support
프레임워크 지향 사용 스타일이란 표현은 빈 팩토리를 쓸 때는 프로그램으로 처리할 내용을 애플리케이션 컨텍스트를 사용하면 선언적으로 처리할 수 있다는 의미다. 나머지 세 가지는 빈 팩토리는 제공하는 않는 기능이다. API 문서를 통해서도 차이를 알 수 있다. Expert One-on-One J2EE Development without EJB에서는 7장에서 설명한다.  블로그를 뒤져보니 일민 형이 예전에 연재한 글 링크가 있다.

J2EE Development without EJB (1) - Why "J2EE Without EJB"?
J2EE Development without EJB (2) - Goal
J2EE Development without EJB (3) - Architecture
J2EE Development without EJB (4) - The Simplicity Dividened
J2EE Development without EJB (5) - EJB, Five Years On
J2EE Development without EJB (6) - Lightweight Container & IoC

토스 97쪽 하단에서 '애플리케이션 컨텍스트는 직접 이런 정보를 담고 있진 않다.'고 설명한다. 이 설명은 애플리케이션 컨택스트를 표현하는 스프링의 ApplicationContext 인터페이스가 상속하는 ResourceLoader 역할을 표현한 내용이다. 그렇다면 실제로 정보는 담는 개체는 누굴까? 관련 글을 2007년 2월에 썼다. 대략의 내용은 유효하지만,  Resource 구현개체가 3.0 에서 두 개가 늘었다. 하나는 AbstractFileResolvingResource 이고, 다른 하나는 VfsResource 이다. javadoc을 보다가 since 표기가 날짜 기준과 버전 기준을 혼용하는 부분이 바뀌었으면 좋겠다는 생각을 해서 이슈로 올렸다. 작년에도 javadoc에 있던 오류를 지적했더니 고쳐준 바 있다. 오픈소스 커뮤니티를 중시하는 회사인지라 피드백이 빠르다.

98쪽부터 3.0 에서 추가된 javaconfig 을 설명한다. 2002년 2월 써둔 글을 보니 클래스 이름도 조금 바뀌었다. 토스 출간 전에 원고형태로 이 내용을 봤을 때는 전율이 흘렀다. 일민 형이 사전에 자랑했음에도 불구하고, 정말 물 흐르는 전개로 스프링 3.0 새로운 기능을 소개하는 방식은 감쪽같고 세련되어 감탄하지 않을 수가 없었다.

99~00쪽 다음 내용을 읽다 보면 반드시 이름이 있어야 한다고 오해할 수 있다.

그런데 UserDao를 가져오는 메소드는 하나뿐인데 왜 굳이 이름을 사용해야 할까? 그것은 UserDao를 생성하는 방식이나 구성을 다르게 가져가는 메소드를 추가할 수 있기 때문이다.

스프링 3.0에서는 BeanFactory 인터페이스에 <T> T getBean(Class<T> requiredType) 메소드를 추가해서, 클래스가 하나 뿐인 경우에 빈 이름을 생략할 수 있다. 편리하긴 하지만, 둘 이상의 빈이 필요해질 가능성이 있다면 애초부터 이름을 붙여주는 편이 좋을 지도 모르겠다. 토스 102쪽에서도 타입만으로 빈을 찾는 메소드가 있음을 소개한다. 1.5 절 마무리하며 다시 한번 용어/개념을 정확히 짚고 넘어간다.

때로는 컨테이너라는 말을 떼고 스프링이라고 부를 때도, 바로 이 스프링 컨테이너를 가리키는 것일 수 있다. 예를 들어, "스프링에 빈을 등록하고"라는 식으로 말하는 경우에 스프링이라는 말은 스프링 컨테이너 또는 애플리케이션 컨텍스트를 가리키는 말이다.

대개 개발자가 '스프링'을 언급할 때, 정확하게 스프링이 제공하는 자원 중에 무엇인지 혹은 어느 영역인지 정확히 인지하지 못하고 말하는 경우가 있다. 스프링에 대해서만 그렇지도 않지만, 무언가 배울 때는 내가 다루는 내용이 무엇인고, 무엇은 아닌지 이해하려고 노력해야 한다. (말이 좀 꼬이네.. 그만 쉬어야 할 때다.)

예전에 그린 그림이 떠올랐다.


출처: 어제 했던 말들을 반추하며

설정

트랙백

댓글

불후의 명작 전략 패턴에 대해서 제대로 알게 된 계기는 스프링이다. 하지만, 가치를 인식하기 시작한 시점은 일민 형이 평소 전략 패턴에 대해 힘주어 말하였기 때문이기도 하다. 토스(토비의 스프링 3 를 줄여서 앞으로 토스로 칭함.) 1장 초반부는 너무 쉽게 전략 패턴을 익히도록 유도한다. 가장 효과적인 방식이지만, 다른 책에서는 GoF 해설에 치중하고 있는데 반해 토스는 체득 후 이론으로 정리한다. 물론, 짧은 연습만으로 전략 패턴에 대해 모두 알고 있다고 말하긴 어렵긴 하다.

§ 1.4 제어의 역전(IoC)
역시 주옥같은 내용이다. 첫 번째로 소개하는 개념은 팩토리(Factories)다. 스프링을 사용하면 반드시 듣는 용어이지만 그리 간단하지는 않은 개념이다. 토스를 보면 팩토리가 GoF의 추상 팩토리 패턴이나 팩토리 메소드 패턴과 다르니 혼동하지 말라고 경고한다. 사실 팩토리 자체 개념을 놓고 보면 다른 내용이 아니다. 굳이 구분하자고 하는 이유는 설계 패턴에서 다루는 두 가지 패턴의 내용과 팩토리 패턴이 다루는 문제의 범주가 달라서 뭉뚱그려서 생각하면 모르는 편이 나을 수도 있기 때문이다. :)

팩토리 개념을 잘 정의한 책이 있다. 에릭 에반스(Eric Evans)의 DDD(Domain-Driven Design) 책이다. 책 136쪽을 보면 자동차 제조 공장 사진이 있고 바로 아래 다음과 같이 정의한다.

When creation of an object, or an entire AGGREGATE, becomes complicated or reveals too much of the internal structure, FACTORIES provide encapsulation.

이야기가 길어질 수 있으니 합성체(AGGREGATE)를 논외로 하면, 개체 생성 과정이 복잡해지거나 내부 구조나 지나치게 많이 드러나면 팩토리('개체 공장'이라고 쓸 용이가 나지 않네.)로 감쌀 수 있다. DDD 책 137쪽을 보면 굵은 글씨로 핵심을 잘 설명하는데 그중에서도 핵심 문장만 골라 번역하면 이렇다.

개체 생성은 그 자체로 주요한 연산(operation)이다. 그러나 복잡한 조립 연산 책임을 생성 대상 개체에 지우는 일을 적절치 않다.

적절치 않은 책임을 개체에 지우면 자연스레 응집도 하락과 결합도 상승을 가져온다. DDD 책은 이후에 팩토리 설계 전략을 설명한다. 설명하는 내용은 이미 9년 전 GoF가 정리한 설계 패턴 중에서 생성 패턴(Creatational Patterns)과 겹친다. 길게 설명했는데 토스에서 '팩토리가 GoF의 추상 팩토리 패턴이나 팩토리 메소드 패턴과 다르다'라고 한 말을 명확히 하려는 의도다. 정리하면 팩토리는 복잡한 개체 생성 과정 자체를 책임으로 갖는 개체고, 추상 팩토리 패턴이나 팩토리 메소드 패턴은 이러한 팩토리를 만드는 여러 가지 방법 중에서 빈번하게 나타나는 설계 패턴을 지칭한다.

92쪽 소제목인 설계도로서의 팩토리는 조금 어색하다. 의도를 알 듯도 하지만 '설계도'란 표현은 영 와 닿지 않는다. 그렇다고 대안은 선뜻 떠오르지 않는다. 95쪽에서 프레임워크를 제어의 역전을 구현한 기술로 소개하며, '프레임워크가 단지 미리 만들어둔 반제품이나 확장해서 사용하는 추상 라이브러리 집합'은 아니라고 한다. 또한, 툴킷, 엔진, 라이브러리와 프레임워크는 다르다고 지적한다. 모호한 개념 정의가 가져오는 폐단을 잘 알기 때문에 필자의 의도는 충분히 공감한다. 개념 오용이나 남발에 대해 이미 여러 차례 생각을 정리한 바 있다.
한편 일민 형이 용어 정의에 대한 소신을 쓴 글을 찾을 수 있었다.
아래 그림은 제3회 아키텍트 대회 발표 자료에 넣었던 프레임워크에 대한 현장 인식 상황을 도식화 한 그림이다. 프레임워크에 대한 요구사항을 말할 때는 전문가가 아니므로 자연스럽게 자기 필요에 의해 규정한 의미를 사용한다. 하지만, 개발자가 프레임워크를 쓰거나 만들기 위해서 프레임워크를 말하는 경우라면 더 엄밀해야 한다. 토스 1.4.3절에서 말하는 프레임워크는 특히 IoC 제공자 역할을 강조하는 문맥이다. 프레임워크가 있기에 사용자 코드는 제어 부담을 줄일 수 있다. 그런 면에서 단순 반제품과 라이브러리와는 다르다.


위키피디아 용어 해석을 찾아보고 넘어가야겠다.

In computer programming, a software framework is an abstraction in which common code providing generic functionality can be selectively overridden or specialized by user code providing specific functionality. Frameworks are a special case of software libraries in that they are reusable abstractions of code wrapped in a well-defined Application programming interface (API), yet they contain some key distinguishing features that separate them from normal libraries.

Software frameworks have these distinguishing features that separate them from libraries or normal user applications:

  1. inversion of control - In a framework, unlike in libraries or normal user applications, the overall program's flow of control is not dictated by the caller, but by the framework.[1]
  2. default behavior - A framework has a default behavior. This default behavior must actually be some useful behavior and not a series of no-ops.
  3. extensibility - A framework can be extended by the user usually by selective overriding or specialized by user code providing specific functionality.
  4. non-modifiable framework code - The framework code, in general, is not allowed to be modified. Users can extend the framework, but not modify its code.

위키피디아 정의에 따르면 프레임워크는 특수한 라이브러리로서 이를 구분 짓는 특성을 네 가지로 정리한다. 제어의 역전, 기본 행위 제공, 확장성, 수정 불가 코드 등이다. 제어의 역전은 토스에서 설명하는 바이고, 수정 불가 코드는 역시 OCP로 다뤘다. 3, 4번만으로는 프레임워크를 일반 라이브러리와 구분짓기 어렵다. 2번인 기본 행위 제공은 제어의 역전이 있기에 가능하다. 프레임워크가 제어권을 갖고 사용자 코드를 호출할 시점에 사용자가 지정한 내용이 없으면 미리 준비한 기본 행동을 제공할 수 있기 때문이다. 그런 점에서 프레임워크를 일반 라이브러리와 구별 짓는 가장 큰 특징은 바로 제어의 역전이다.

토스에서는 이미 코드 변경을 통해 체득한 제어의 역전 개념을 잘 정리했다. 글 전개 측면에서 한 가지 아쉬운 점이 있는데, 말미(96쪽)에 이런 내용이 나온다.

단순한 적용이라면 DaoFactory와 같이 IoC 제어권을 가진 오브젝트를 분리해서 만드는 방법이면 충분하겠지만, IoC를 애플리케이션 전반에 걸쳐 본격적으로 적용하려면 스프링과 같은 IoC 프레임워크의 도움을 받는 편이 훨씬 유리하다.

무리한 내용은 아니지만 토스 1장이 실습을 하고 체득 후 개념 정리를 했는데, 아직 'IoC를 애플리케이션 전반에 걸쳐 본격적으로 적용'하기 위해 무엇이 필요한지 이야기가 나오기도 전에 역시 아직 소개되지 않은 스프링의 다른 기능이 필요하다고 표현했다. 사실 이런 내용은 모두 뒤이어 나온다. 그래서 96쪽에서 미리 스프링을 쓰라고 권장하지 말고, 독자가 스스로 판단하게 했으면 어떨까 하는 생각이다.

마무리하려고 보니 다시 툴킷, 엔진과 프레임워크 구분에 대해 찜찜함이 남아 위키피디아를 찾는다. 툴킷(SDK)는 개발 도구 집합이며, 프레임워크 사용을 지원하는 역할을 한다. 엔진(소프트웨어 엔진)은 프로그램 코어를 의미한다. 제어의 중심이라는 의미보다는 기능을 주도하는 코드를 말한다.

A software development kit (SDK or "devkit") is typically a set of development tools that allows for the creation of applications for a certain software package, software framework, hardware platform, computer system, video game console, operating system, or similar platform.

출처: http://en.wikipedia.org/wiki/Software_Development_Kit


In computer science, a software engine refers to the core of a computer program. Software engines drive the functionality of the program, and are distinct from peripheral aspects of the program, such as look and feel.

사실 용어 정의가 어려운 이유는 개념과 실제 현상이 1:1 대응이 아니기 때문이다. 그래서 용어나 개념이 규정하고자 하는 바(Concern)를 구분해서 봐야 한다. SoC와 같은 사고법은 소프트웨어 설계뿐 아니라 정확한 개념 이해나 용어 정의에도 유익하다. 

설정

트랙백

댓글

§ 1.3 DAO의 확장
새로운 절을 시작하는 글에서 다시 지침으로 쓸 만한 의견을 제시한다.

변화의 성격이 다르다는 건 변화의 이유와 시기, 주기 등이 다르다는 뜻이다.

분리할 관심사를 선정할 기준으로 생각할 수 있다. 74쪽부터 이어지는 클래스로 분리하는 과정은 GoF 책 18쪽부터 이어지는 상속(inheritance) 대 합성(composition)을 몸(?)으로 익히는 흐름으로 투자 대비 효과(ROI)가 탁월하다. 개념을 다지는 방편으로 1.3.1 학습 이후에 GoF 책 18~21쪽을 읽어볼 수 있다.

Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional Computing Series) (Hardcover) - 10점
Gamma, Erich/ Helm, Richard/ Johnson, Ralph/ Vliss/Addison-Wesley Professional

참고로 75쪽에 메소드 이름에 오타가 있는데 출판사 홈페이지에 정오표가 있다. 1.3.2 인터페이스 도입은 역시 GoF 책 17~18쪽에서 개념 정리를 위한 보충 설명을 찾을 수 있다. 로드 존슨(Rod Johnson)이 쓴 J2EE 설계와 개발에 대한 첫 번째 빨간 책을 본 사람은 토비의 스프링 3 1장 내용과 빨간 책 4장 내용이 비슷한 내용을 다루고 있음을 알 수 있다. 사실 둘을 비교하는 일은 무의미하지만, 토비의 스프링 3에서만 찾을 수 있는 내용은 잘 그린 UML 도해다. 언젠가 일민 형이 메신저로 자꾸 UML 문법을 물어본 일이 있다. 링크(Link)나 관계(Relationship), 의존 관계(Dependency) 등에 대해 꼬치꼬치 물었다. 1장의 UML 도해는 당시 그린 그림이다. 호주산 EA도 시도했는데, 결국 가장 예쁜 그림을 위해 오피스에서 도형으로 직접 그렸다. 사실 컨설팅 과정에서 UML이 필요한 경우도 오피스에서 그린다.

Expert One-On-One J2Ee Design and Development (Paperback) - 10점
Johnson, Rod/John Wiley & Sons Inc

당시 일민형은 기본적인 UML 표기법을 묻는 것이 아니라 의존 관계와 관계의 인스턴스 성격인 링크에 대해 물었다. 관계가 클래스라면, 링크는 인스턴스이다. UML 관계에 대해 정확히 기술하려면 명세를 봐야 하는 처지라 생략하겠다. 하고 싶은 이야기는 UML 자체가 아니라 그림 1-5를 봤을 때 놀라움이다. 불필요한 의존 관계를 제거하여 결합도를 줄여야 하는 필요성 그리고 과정에서 인터페이스를 사용해야 하는 이유를 UML 하나로 설명했다. 이 그림을 처음 봤을 때 너무 짜릿했다. 보이지 않는 내용을 눈으로 보게 해주는(visualization) UML 이점을 제대로 활용하는 모습을 목격했기 때문이다. 나름 UML 전문가라 떠들며 CBD 컨설팅을 할 때 왜 굳이 서비스와 DAO 계층에 인터페이스를 두어 파일을 두 배로 만드느냐고 묻는 개발자에게 구구절절하게 설명하던 기억이 떠올라 머쓱했다. 쩝.


이 그림은 잘 그린 명작은 아니지만, UML을 제대로 활용한 대표적 사례다. 그래서 일민 형 허락을 받아 책 출간 전에 모 회사에서 강의할 때 사용했다. 인터페이스 필요성을 설명할 때 이만한 그림이 없다. 웬만한 UML 전문가라는 이보다 UML 활용을 훨씬 잘했지만 미세한 오류는 있다. 81쪽에 나오는 '오브젝트 사이에 다이내믹한 관계'와 같은 표현이나 82쪽에 나오는 '오브젝트 사이의 관계가 만들어진 상태' 등의 표현은 UML 맥락에서는 오류다. 오브젝트를 다이내믹한 클래스라고 부르지 않는 것처럼 링크를 다이내믹한 관계라 부르지는 않기 때문이다. 굳이 따지자면 그렇지만, 내용 이해에는 문제가 없다.

1장 읽고 토론하는 자리에서 P님이 일반 업무시스템에서 계층마다 기계적이다 싶을 정도로 적용한 인터페이스에 대한 경험담을 공유했다. 인터페이스나 구현체만 따로 바꿀 일이 거의 없는 서비스와 DAO에도 모두 일괄적으로 인터페이스를 만드는 일이 과연 가치 있나 고민했다고 한다. 공감할 수 있는 일이다. 그런데 나중에 전체 업무를 파악하는 데에는 유익했다고 설명할 때, '코드의 ERD'란 표현이 떠올랐다. 종종 현행업무를 분석하는 ERD도 없는 사이트를 보곤 하는데 마찬가지로 현행업무에 제대로 이름을 붙인 인터페이스가 있다면 코드 구조나 주요 기능을 파악할 때 큰 도움이 될 것이 분명하다. 

개방 폐쇄 원칙
사례를 통해 체득한 내용을 정리하는 내용이다. 이론 중심으로 이해하면 실전 적용에선 막히는 일이 많다. 그런 면에서 실습으로 체득하고 개념을 잡기 위해 정리하는 책의 기술 방식은 매우 효과적이다. SOLID에 대한 내용은 지난 마소 기사를 인터넷에서 볼 수 있으니 필요한 만큼 참조할 수 있다.

zdnet - 객체지향 SW 설계의 원칙 ① 개방-폐쇄 원칙
zdnet - 객체지향 SW 설계의 원칙 ② 사례연구, 단일 책임 원칙
zdnet - 객체지향 SW 설계의 원칙 ③ 인터페이스 분리의 원칙
zdnet - 객체지향 SW 설계의 원칙 ④ 리스코프 치환 원칙

내 블로그의 관련 글도 옮겨둔다.

cohesion, TDD 그리고 SRP(Single Responsibility Principle)

높은 응집도와 낮은 결합도
응집도와 결합도는 구분해서 생각할 수 없다. 개체의 응집도와 결합도는 같은 현상에 대해 바라보는 다른 시각을 정의한 개념이다. 개체 경계는 설계자 인식에서 출발한 인위적인 내용이다. 아래는 이런 생각을 설명하기 위해 머릿속으로 떠올린 그림이다. 그림과 같은 겹치기도 하고 관계도 명확하지 않은 경계를 정리해서 온전한 개체를 만드는 일 자체가 설계이기도 하다. 설계에 대해 이처럼 인식하다 보니 Object에 대한 우리 말로 객체보다는 개체(個體)가 적합하게 느껴진다.



적당한 설계를 구분하는 지표가 무얼까 고민하면 "Atomic"이란 단어가 떠오른다. 더 쪼갤 수 없을 만큼 단단하게 느껴지는 개체, 거기서 더 쪼개면 본래 특성이 사라지는 수준. 다른 말로 표현하는 응집도가 최고조에 달한 상태다. 반면에 응집도가 약해졌다는 의미는 특성이 빠져 있거나 관계가 빈약한 특성을 함께 포함한다는 의미다. 전자는 다른 개체에 그 특성이 있다면 의존해야 하기 때문에 결합도가 높아진다. 후자는 서로 다른 목적으로 접근하는 개체가 늘어나는 이유로 결합도가 높아진다.  아래 발췌한 토비의 스프링 3 87쪽 내용을 보면 부작용에 대해 구체적인 예를 든다.

만약 모듈의 일부분에만 변경이 일어나도 된다면, 모듈 전체에서 어떤 부분이 바뀌어야 하는지 파악해야 하고, 또 그 변경으로 인해 바뀌지 않는 부분에는 다른 영향을 미치지 않는지 확인해야 하는 이중의 부담이 생긴다. <이하에 이어지는 구체적인 사례 생략>

"Atomic" 개체를 만드는 일이란 말처럼 쉽지 않지만, 그래서 처음부터 완벽하게 설계하는 진화형 모델이 주류로 부상하는 듯하다. 몇 년 전에는 Unified Process 등이 표방하는 반복/진화였다면 최근에는 애자일에서는 JIT(Just-in-time)를 거론한다. 다른 분야에서 복잡한 설계를 할 때 시뮬레이션을 하는데, TDD에서 활용하는 단위 테스트에서 시뮬레이션과 유사한 효과를 얻는다고 느꼈다. 또한, 단위 테스트를 하면 자연스럽게 병행하는 리팩토링은 '티끌 모아 Atomic 객체'를 만드는 생산적인 활동이다.

88쪽에 '낮은 결합도는 높은 응집도보다 더 민감한 원칙'이라고 소개했지만, 응집도를 높이면 결합도는 낮아진다. 아마 개발자가 체감하는 정도에서 결합도가 더 민감하다는 표현을 이렇게 쓴 듯하다. 하지만, 누군가 결합도가 뭐냐고 묻는다면 저자의 정의를 인용해도 좋을 듯하다.

결합도란 '하나의 오브젝트가 변경이 일어날 때에 관계를 맺고 있는 다른 오브젝트에게 변화를 요구하는 정도'


설정

트랙백

댓글

§ 1.1 초난감 DAO
초난감 DAO를 예로 선정한 점은 일민 형의 내공과 통찰을 보여주는 증표다. 일민 형이 워낙 좋아하면서 수줍어해서 내가 나서 말을 걸었던 롭 해롭(Rob harrop)에게 물었다. 스프링 구성요소 중에서 가장 좋아하는 기술은 무엇이냐고. 롭은 개인 의견을 내세우는 대신 고객을 빌렸다. 스프링소스의 최대 고객인 JP 모건에서는 스프링 기술 중에서 하나만 사용한다는 일화로 대답을 대신했다. 그것이 바로 JDBCTemplete 다. 가만 생각해보면, J2EE/Java EE 기술 중에 팥소는 JDBC다. EE 영역에서는 여전히 데이터베이스 중심으로 처리한다. 데이터베이스의 본질인 데이터 관리뿐 아니라 동적인 측면인 거래 처리까지 데이터베이스에 의존한다. DB 연결 누수로 서비스를 주기적으로 내렸다 올려야 하거나 시스템 오픈을 못하는 일을 2006년까지 목격했다. 하지만, JDBCTemplete를 이용하면 쉬운 문제다.



토비의 스프링 3 61쪽에 밑줄 친 내용이 있다.

초난감 DAO 코드를 객체지향기술의 원리에 충실한 멋진 스프링 스타일의 코드로 개선해보는 작업을 할 것이다.

스프링 스타일이라는 표현은 모호하지만, 무슨 의미인지 뒤이어 나오는 내용을 통해 추측할 수 있다.

스프링을 공부한다는 건 바로 이런 문제 제기와 의문에 대한 답을 찾아나가는 과정이다. 스프링은 기계적인 답변이나 성급한 결론을 주지 않는다

스프링은 본말이 전도되는 일을 치밀하게 막고자 한다. 한때, 스프링이 지나치게 복잡하다고 주장하는 이가 있었다. 스프링이 추구하는 본질을 몰랐기 때문이다. 디자인 패턴도 쓰임새와 필요성을 모르면 지나친 설계 왜곡으로 보일 수 있다. 또, 스프링을 비롯한 프레임워크때문에 개발자 수명이 줄어든다는 의견 제기도 있었다. 얼핏 맞는 의견 같지만, 스프링 대신 객체지향설계나 디자인 패턴을 가르쳐 주는 방법이 무엇이 있을까? 나는 스프링 소스코드를 보기 전까지 많은 디자인패턴 책을 봤지만, 코드에 적용할 엄두를 내지 못했다. 단위 테스트(자동화)는 어떤가? 역시 스프링 테스트 코드를 보기 전까지는 DB를 쓰고, 컨테이너가 필수인 J2EE/Java EE 환경에서 테스트를 시도했던가? 프레임워크를 쓰기 때문에 애플리케이션 내부 작동방식이나 구성원리를 모르고 API만 아는 개발자로 전락한다는 발상은 아주 틀린 이야기는 아니다. 하지만, 오픈소스 형태의 프레임워크는 오히려 반대다. 마음만 먹으면 책이나 테스트를 통한 학습(라이브러를 쓰면서 이것저것 해보기)외에 소스코드를 직접 볼 수 있고, 심지어 SVN 저장소를 통해 발전 과정에서의 코드 변경 이력까지 볼 수 있다.


§ 1.2 DAO의 분리
변화를 대비하는 자세는 기본이다. 지금 날씨가 맑아도 비가 올 가능성이 있다면 우산을 준비한다. 일민 형이 그 부분을 정말 잘 설명했다. 사실 관심사의 분리(Separation of concerns)는 쉬운 주제가 아니다. 꼼꼼쟁이 일민 형이 이 내용을 쓸 때 다른 사람 의견을 찾느라 SoC 관련 포스팅을 찾아다닌 것으로 안다. 그러다가  SoC에 대해 오해를 유발할 수 있는 글에 대해 일민 형이 댓글을 달았으나 필자가 감정적으로 대응했다. 채팅으로 답답함을 호소했는데 마침 술 마시고 귀가한 날 약간 자극적인 글을 썼다. 상대를 알아보고 썼어야 했는데 실수였다. 어떤 마음에서 썼는지 솔직히 잘 모르겠다. 하지만, 노OOO님처럼 막말에 가까운 비판이나 비방은 아니었다. 딴에는 스스로 자꾸 거만해지는 모습을 우려해서 종종 자아비판도 하는 터라 비판의 수위는 높다고 생각하지 않았는데, 결과는 최악으로 흘렀다. 다행히 봉합은 했지만, 못내 아쉬웠다. 최근에도 패턴 전문가로 활동하시는 분이기에 SoC에 대해 이해가 더 성숙해질 수 있는 계기였는데, 감정싸움으로만 귀결되었다. 이미 일 년 반 전의 글인데 내가 쓴 글에서 크게 충격을 받았다고 해서 지워 버렸다. 당시 정황을 공유할 방법은 없지만, 공감하는 글을 다시 찾을 수 있어서 공유한다.

Separation of Concerns (SoC)

마지막 문장은 당시 굳이 시간을 내서 비판했던 이유이기도 하다.

어떤 다른 뜻이 있었는데 표현을 적절하게 하지 못한 것인지 아니면 정말 SoC 때문에 그러한 고통이 온다고 생각했는지는 모르겠지만 위의 포스트를 읽고 SoC를 단순히 코드의 분리로 이해해서 SoC 때문에 클래스가 조각난다는 생각을 갖는 사람들이 없기를 바란다.


어쨌든 SoC에 대한 설명은 토비의 스프링 3에서 놀랍게도 명쾌하게 설명했다. 왜냐하면, 단어만으로 전달하는 대신 실습(practice)으로 몸에 익히는 방식을 취했기 때문이다. 초난감 DAO가 포함하는 여러 가지 관심사를 순서대로 나누는 접근은 탁월하다. 책의 효과를 더 높이려면 독자는 코드를 작성해보길 권한다. 타자하는 과정에서 몸이 기억하는 효과도 얻지만, 무엇보다 책으로 휙 넘겼을 때보다 사고하고 소화할 시간을 충분히 벌 수 있기 때문이다. SoC랄 표현을 가장 먼저 썼다고 알려진 사람은 컴퓨팅 분야의 거성인 에드가 다익스트라다. 1974년 논문 'On the role of scientific thought'에서 처음 쓰인 이후로 설계 원칙으로 널리 회자 되었다. 위키피디아에서를 보면 TCP/IP 프로토콜의 계층(layer) 구분과 AOP 등을 예로 들고 있다. 전형적인 사례인데 조금 사고를 확장하면 새로운 사례를 찾을 수 있다.

켄트 벡(Kent Beck)의 책에서 TDDBE에 서 가장 감명을 받은 내용은 적절한 작업 분량을 떼어 내면서 리듬을 찾는 방법이다. 엉클 밥(Uncle Bob)의 볼링 카타에서는 구체적인 사례로 보여주기도 한다. 이러한 분할 역시 SoC라고 할 수 있다. 작업 시간을 짧게 나눈 후에 관심사를 명확하게 나누어 테스트를 작성하는 방법도 SoC 응용이다. 켄트 벡(Kent Beck)은 저서인 구현패턴(Implementation Patterns)을 통해 극한의 SoC 활용 사례를 보여준다. 프로그램 작성 진도를 늦추면서, 자신의 사고 과정 자체를 추적하여 미세한 관심사를 패턴으로 정리하는 일 말이다. 머리로는 이해가 가지만, 과연 실천할 수 있을지 싶은 놀라운 능력과 인내다.

위키피디아 설명을 보면 관심사 분리 방법으로 모듈 작성이나 캡슐화(encapsulation)를 들고 있다. 토비의 스프링 3에서는 모듈화나 캡슐화 실현 방법으로 리팩토링을 소개한다. 리팩토링은 수학에서 배운 인수분해가 떠오르게 한다. 리팩토링에 해당하는 우리 말은 뭘까? 재구성(Re+Factor+ing)?

앞서 발췌한 내용처럼 객체지향 설계의 3요소에 리팩토링과 단위 테스트를 포함한 점은 매우 적절하다. 단위 테스트가 모여 만든 회귀 테스트는 리팩토링에 대한 막강한 후원자가 된다.

이후에 전개하는 내용은 유연성 측면에서는 상속보다 위임이 좋다는 사실에 기초한다. 하지만, 항상 그렇지는 않다. 소규모 집단이 많은 개발자 코드 사이에서 일관성을 유지하려는 경우는 상속이 좋다. 상속을 통한 템플릿 메소드 패턴(template method pattern)이 대표적이다. 69쪽 이후의 내용은 다음 이 시간에 GoF 책을 인용해서 정리하려고 한다.

책 읽고 토론하기 모임에서 P군이 프레임워크 유지 보수와 지원 담당자 시절 경험을 공유했다. 처음에는 상속을 사용하여 개발팀의 코드를 일관성 있게 통제하는 점이 상당한 이점이었지만, 시간이 흐르면서 기존 구조에서는 충족하기 어려운 요구 사항이 생기면서 상속의 문제가 드러났다는 경험담이었다.

성급한 일반화인지 모르지만, 통제권 안에 있는 코드 즉, 지역적으로나 소속이 같은 팀에서 작성한 코드는 상속을 써서 강한 통제를 하고 관련 코드를 유착시켜서 얻는 이점이 있다. 물론, 시스템 오픈 이후에도 수정할 일이 많은 경우라면 예외라 할 수 있다. 반면에 멀리 떨어진 조직이나 소속이 다른 팀에서는 상속은 장애물로 작용할 수 있다. 이런 경우는 JDBC 드라이버(혹은 데이터소스 관리 라이브러리)에서 널리 쓰인 인터페이스와 구현체 분리가 굉장한 효과를 발휘한다.

마침 얼마 전 만난 Method Chain 개발자가 직접 말씀해주신 내용이 생각났다. 자바 스크립트 상속으로 구현한 코드 베이스를 '필요할 때 new로 생성하는 방식'으로 고치는데 상당한 시간이 걸린다고 했다. 상속이 스크립트 API 편의성 측면에서 장점이 많지만, 모바일 버전 개발할 때는 문제라고 한다. 자바스크립트는 잘 몰라서 '필요할 때 new로 생성하는 방식'이 위임인지는 모르겠으나 비슷하지 않을까 싶어 흥미로웠다.

설정

트랙백

댓글

팀 내에서 주 1회 토비의 스프링 3을 읽고 토론을 한다. 지난주 금요일이 첫 시간이었다. 밀린 회사 일이 있어서 20분 정도면 충분하겠거니 생각하고 시작했다. 한 친구가 시간을 측정했는데 정확히 1시간 30분이 걸렸다. 요즘 딸 아이를 얻어 행복한 P씨 말에 따르면 책을 읽을 때는 별생각이 없었는데, 사람들과 이야기 하다 보니 여러 가지를 생각하게 되어 좋다고 했다. 공감. 책 읽고 토론하는 자리는 적극적인 발언자가 있지 않으면 진행이 쉽지 않다. 말하기 좋아하는 내 성향과 가장 나이가 많다는 점 때문에 자칫하면 혼자 강의하는 식이면 소모적인 자리일 수 있어서 조심스러웠다. 진행은 우선 사회자(나)를 두었다. 각 장을 구성하는 절 순서로 토론했다. 사회자가 해당 절의 줄거리를 짧게 환기하고 의견을 기다리는 식으로 진행했다. 기록을 남기기 위해 회의록을 쓰자고 했지만, 어차피 이 글이 회의록을 대체할 테니 의무감으로 쓰지는 않기로 했다. 서기(나)도 둔 셈이다. 다만, 못다 한 이야기를 반추하는 의미에서 알아서 투고(稿)[각주:1]하기로 했다. (검사해야지.. ㅋㅋ)

어차피 이 책을 지금처럼 꼼꼼하게 다시 읽어볼 기회는 없을 것이다. 그래서, 한 글자도 빠뜨리지 않고 꼼꼼하게 읽고 정리할 셈이다. 내 소감과 토론을 덧붙여 쓰다 보면 초점이 사라질 우려가 있어서 토비의 스프링 3 읽고 토론하기 17주 프로그램 소개에서 밝힌 목적을 상기시켜보자.

  1. 책 내용 알리기
  2. 교재 초안 작성
  3. 토론 촉발

§ 1장 전체와 도입부를 읽고 느낀 점
아직 책을 다 읽지도 않았지만, 1장은 이 책 최고의 작품이다. 앞서도 소개한 바 있는 코드 진화를 축으로 하는 책의 전개 방식은 이 책을 다른 책과 구분을 지어주는 핵심 특성이다. 그리고 아마도 많은 독자에게 그간 고민해보지 않았던 문제에 대해서 초심으로 돌아가 생각할 기회를 줄 것이라 믿기에 단언할 수 있다. 훌륭한 내용은 노력의 산물이고, 때로는 고통의 산물이다. 일민 형이 블로그에 쓴 후기를 오해하는 분이 많아 배경을 소개하는 글을 남겨둔다. 최근에 프로젝트를 함께 하는 K과장님은 아래 글을 읽고 얼마나 '심하길래' 하고 책을 봤다가 '괜찮은데 왜 그랬지'라는 의문을 품었다고 한다.

2장을 쓰는 중에 영회가 자꾸 책 진도를 물어왔다. 그래서 1장을 마쳤으니 한번 읽어보라고 1장 원고를 넘겨줬다. 2장은 완성되면 줘야지 하고 아직 넘기지 않았다. 진득하게 기술을 공부하고 연구하는 것보다는 사람들과 어울려서 수다떠는 것을 더 좋아하는 영회인지라 원고가 넘어가고도 한참이 지나서야 겨우 읽은 듯 했다. 다 읽었다고 하길래 어땠냐고 물어봤다.

그 질문을 한 것이 일생일대의 실수였다.

돌아온 영회의 피드백은 충격적이었다. 사실 기대한 것은 스프링에 대해서 이렇게 설명하는 것보다는 이렇게 하는 것이 좀 더 이해하기 쉽지 않겠냐라든가 스프링의 정의에 이런 요소를 넣었으면 좋겠다와 같은 실제 1장의 의도에 맞는 분석이나 제안이었다. 하지만 영회는 원래 그런 것에 별 관심이 없다. 평소에 문과 출신이고 IT계에서 흔치 않게 인문학적 소양이 높다는 점을 자랑했듯이 돌아온 피드백도 스프링의 기술과 본문의 내용과는 상관없는 단순 인상비평이었다.

<중략>

위기가 왔다.

속도 상하고 화도 많이 났다. 책을 쓴다고 5개월 가까이 투자해 왔는데 건질게 없는가 해서 좌절감이 몰려왔다. 나는 책을 쓸 자질이 없다는 생각이 들었다.

<중략>

그렇게 다시 며칠을 마음을 비웠다. 그리고 그 때까지 쓴 1,2장 원고를 모두 버렸다.

출처: http://toby.epril.com/?p=1098

보통 블로그에 투고한 긴 글은 꼼꼼하게 읽지 않는 사람이 많다. K과장님도 내용은 기억하지 못하고 1장에 대해 내가 지적했다는 단편적인 기억만 간직했다. 또한, 일민 형도 오랜 기억인지라 사실은 부정확하고 감정만 생생하게 남았다. 글에는 소개가 없었지만, 여느 책처럼 추상적인 내용으로 시작하지 않기를 바랐다. 아래 일민 형 글에 나오지만, 본인도 따분한 1장은 쓰기 싫다고 했다. 하지만, 코드로 바로 들어가는 것은 거부했다. 당시 내 비판적인 피드백의 배경에는 문과 출신(엄밀히 말하면 상대 출신의 이학석사다.)이 갖는 문학적 소양보다는 상투적인 출발을 극복할 수 있는 용기에 대한 기대감이 있었다. 말처럼 쉬운 일은 아니지만, 일민 형이라면 할 수 있을꺼라고 봤다. 지금 보니 채팅으로 나눴던 대화에서 의도는 100% 잘못 전달된 모양이다.

서문을 마치고 1장을 시작했다. 나도 다른 책의 따분한 1장이 싫었다. 특히 기술의 역사가 나오면 가장 짜증났다. 내가 알고 싶은 것은 지금 내가 사용할 버전의 기술이지, 장황한 기술 역사와 그 역사를 꿰고 있다는 저자의 자랑이 아니었다. 물론 그렇다고 특정 기술설명이나 코드로 바로 들어가는 것은 적절해보이지 않았다. 스프링을 예제와 사용법 위주로 공부하면 전체를 꿰뚫는 프로그래밍 모델과 철학을 놓치기 쉽다. 프레임워크를 사용하는데 개발철학 따위야 꼭 필요한 것은 아니지만 스프링은 예외다. 스프링은 기본을 알면 이해하고 응용하기가 아주 쉬운데 그렇지 않고 개별 기술을 따로 따로 공부하면 그 방대한 양에 금세 지쳐버린다. 게다가 스프링 만큼 오해가 많은 것도 없다. 그래서 일단 1장에서 스프링이란 도대체 뭐고, 뭐에 쓰는 것이고, 스프링이 어떤 유익을 주는지에 대해서 적기로 했다.

결과적으로는 일민 형은 해냈다. 조금 미화하면 용기있는 초보 저자로 탄생하는 출발점은 내가 제공했다. 여러분이 보고 있는 아름다운 1장에 2%는 나의 노력임을 기억해주길 바란다. (농담) 가끔 스스로 대견하다 싶은 놀라운 생각을 할 때가 있다. 처음에는 자아도취 기회로 삼았다. 그러나 시간은 많은 것을 가르쳐 준다. 어느 날인가 고객인 J차장님과 대화하던 중, 이런 생각은 공공재라는 말을 했다. 내 생각과 노력만으로는 뛰어난 결과를 만들기 어렵다. 역사를 거친 수많은 사람의 노력이 나를 통해 실현되었을 뿐이라는 생각은 살면서 시나브로 주입되었다는 점은 여간 다행스러운 일이 아니다.

날려버린 1장을 처음 쓸 때 사실 힘들었다. 그 1장에는 코드 한줄 나오지 않는다. 대신 3만피트 상공으로 올라가서 스프링 세계를 내려다보며 스프링이 이렇게 생겼네라고 구름 위에서 얘기하듯이 설명하는 내용이다. 그래서 신경쓸 것은 단어, 표현 등이었다. 함축적인 단어를 어떻게든 잘 골라서 이런 저런 스프링의 특징을 깔끔하게 묘사해야 할텐데라는 고민으로 대부분의 시간을 보냈다.

나는 그런 식의 얘기가 편하지 않다. 내가 가장 편한 시간은 코드를 앞에 놓고 코드에 대해서 이야기 할 때다. 열 줄 정도의 코드만 있어도 재미나게 한 시간쯤은 수다를 떨 수 있다. 지난 27년간 거의 매일 만들고 다듬고 뜯어보고 감상해왔던 것이 코드다. 그래서 누군가에게 기술을 설명해줄 때도 코드를 놓고 이야기해야 편하다. 특히 어설픈 코드를 만들어 놓고 그것을 다듬고 발전시켜서 아름다운 코드로 만들어내는 과정을 즐기는 것이 좋다.

출처: http://toby.epril.com/?p=1100


처음 무언가를 시도하면 본 뜰 대상을 찾는다. 레퍼런스라는 우아한 표현으로 위장하지만 결국은 따라하기를 의미한다. 앞서 용기란 표현을 쓴 이유는 일민 형이 쓰는 책은 기존 서적의 틀에 갇히지 않기를 바랐기 때문이다. 위 글에서도 확인하는 바대로 불편한 이야기지만, 책에 대한 고정관념을 벗기는 힘들었을 것이다. 나에 대해 복수의 칼을 간 결과가 이런 도약이라면 악당 역할도 나쁘지 않다.

글이 늘어지는데, YUST에 헌신한 일민 형의 경험도 큰 공헌을 했음을 확인할 수 있다.

나는 이미 이전에 간단한 DAO 코드를 가지고 스프링의 DI를 설명해본 경험이 있다.

<중략>

그래서 향화에게 어떻게 스프링을 가르쳐 줄까 고민하다가 생각한 것이 그나마 향화가 가장 익숙하고 많이 만들어본 DAO였다. 초보 개발자들이 교육센터 등에서 만드는 DAO 수준은 뭐 뻔하다. try/catch/finally라도 적용했으면 다행이고, 그렇지 않은 경우도 많았다. JDBC API를 사용해서 돌아만 가는 CRUD만 만들 수 있어도 잘하는 것이었으니까. 물론 향화는 내가 교육하면서 try/catch/finally나 안전한 DAO를 만드는 방법에 대해서 확실하게 교육했으니 잘 알고 있었지만.

그래서 향화가 그나마 잘 아는 DAO 코드를 하나 만들어줬다. 그리고 그 코드의 문제점이 무엇인지 찾아보고 그 코드를 매일 매일 조금씩 개선하면서 OO적인 코드로 다듬는 것을 알려줬다. 그렇게 짬짬이 원격 교육을 하면서 서서히 DAO코드를 다듬어서 DataSource에 대한 DI도 적용하고 템플릿/콜백도 만들어가는 식으로 설명을 해줬다. 그냥 XML 설정파일 만들고 DAO와 DataSoruce 빈을 등록하고, CRUD는 JdbcTemplate가져다 쓰고, web.xml에 컨텍스트로더리스너 등록해서 돌리라고 가르쳤으면 일주일이면 충분했을 것을 몇 달에 걸쳐서 설명을 해줬다. 하지만 그렇게 스프링을 이해하고 배우는 것이 나중에 내가 더 이상 스프링을 가르쳐 주지 못하고 혼자서 공부할 때 분명 도움이 될 것이라는 확신이 있었다.

어쩌다 보니 책과는 무관한 경험담만 소개했다. 사실 도입부에서 느낀 점은 두 가지다. 다른 책에서 흔히 보여주는 지루한 1장은 깨끗이 사라지고, 일민 형 색깔이 묻어나는 훌륭한 1장이라는 점이 하나다. 일민 형이 장고한 후기를 쓰지 않았다면 저자로서 자아를 바꾸는 과정이 얼마나 힘든 일인지 짐작조차 못 했을 것이다. 두 번째는 책에 나타난 내용에 대한 소감이다.

객체지향 설계의 기초와 원칙을 비롯해서, 다양한 목적을 위해 재활용 가능한 설계 방법인 디자인 패턴, 좀 더 깔끔한 구조가 되도록 지속적으로 개선해나가는 작업인 리팩토링, 오브젝트가 기대한 대로 동작하고 있는지를 효과적으로 검증하는 데 쓰이는 단위 테스트와 같은 오브젝트 설계와 구현에 관한 여러 가지 응용 기술과 지식이 요구된다.
.
한 분야에서 열심히 고민하는 사람이라면 간단하지 않은 개념을 설명할 때 핵심 요소나 특징을 꺼내면서 자연스럽게 균형감 있게 정리하려고 노력한다. 그래서 책을 읽으면서 굵게 표기한 세 단어에 동그라미를 쳤다. 저자가 생각하는 객체지향 설계의 주요 항목이다. 훌륭한 저자라면 이런 생각은 책 전체에 투영하기 마련이니, 행간의 배경으로 쓰인다. 내 경우는 행간의 이해 목적보다 나중에 객체지향 설계에 대해서 정리하거나 토론할 일이 생기면 참조할 목적이었다.
  1. 포스팅 대신 사용 [본문으로]

설정

트랙백

댓글

일민형과의 약속 때문에 쓰는 글인 탓에 목적이 흐릿해 중언부언할 수 있어서 나답지 않게 글을 쓰는 목적부터 써봐야겠다. 17주 프로그램이니까 상당한 시간을 쏟을 테니까 투자한 시간만큼 가치 있는 글을 뽑아내려면 목적을 분명히 써두는 일이 유익할 것이란 믿음으로.

맥스님이 독중감이라는 생소한 표현을 써서 센스 넘치는 글을 썼다. 아이러니하게 독중감이라는 표현 탓에 독후감으로 쓰려던 생각이 바뀌었다. 토비의 스프링 3 은 술술 읽히는 책도 아닌지라 몸소 코딩도 함께해야 한다. 다시 말해서 상당한 시간을 투자하고 생산하는 내용이니만큼 조금 더 욕심을 내야겠다는 생각이 들었다. 더구나 가벼운 마음으로 시작했던 팀 내 토의가 상당히 유익했다. 네 명이 함 1장을 읽고 20분 정도 소감이나 나누자던 자리는 정확히 1시간 반만에 끝이 났다. 그래서, 독후감보다는 저자의 노력으로 만들어진 값진 책에 십시일반 생각과 경험을 더한 기록을 남겨 다만 몇 사람에게라도 생각을 풍부하게 돕는 촉매제가 되길 기대하며 17주의 장정을 시작한다.

토비의 스프링 3 - 10점

글을 쓰는 목적
첫째, 토비의 스프링 3 홍보다. 책이 많이 팔리면 나에게 돌아오는 금전적 보상은 전혀 없다. 그럼에도 책을 홍보하는 이유는 단지 일민 형과의 친분 관계 때문이 아니다. 토비의 스프링 3 은 한글 책으로는 드물게 명서 반열에 올리고 싶은 기술서적이다. 자바 아니 어쩌면 엔터프라이즈 프로그래밍 영어에서 이 정도 비법과와 고민이 담긴 책이 있었을까 싶고, 일민 형이 고생한 시간을 따져보면 앞으로도 이런 책이 나올까 싶다. 물론, 내가 모르는 좋은 책이 있었을 수도 있고, 기억력이 믿을만하지 못한 관계로 지나친 극찬일지 모르지만, 매우 훌륭한 책임에는 분명하다. 좋은 책은 널리 읽혀야 한다. 그래서 넓게 보면 모두 동료인 이 시대의 개발자들의 수준이 향상되기를 기대하는 마음이다. 물론 기대하기 어려운 바램이지만, 일민형이 책이 많이 팔려서 또 유사한 책을 쓰고 싶은 욕구가 생기기도 기대해본다.

둘째, 토비의 스프링 3 에서 사용하는 자연스러운 코드 진화 흐름을 빌린 교재를 만들기 위함이다. 2005년 즈음에 Foundations Of JSP Design Patterns 라는 책에서 처음 봤던 전개 방식이다. 이 책은 빈 조차 쓰지 않는 JSP 코드에서 빈을 뽑아내고, 패턴을 적용해서 궁극에는 프레임워크를 만들어내는 전개 방식을 담고 있었는데, 이런 류의 접근방식을 처음 보았던 터라 신선한 충격이었다. 당시에 자바 개발자 사이의 분위기는 '유행하니까' 스트러츠를 쓰거나 하이버네이트를 쓴다는 식이어서 한국에는 왜 이런 책(원리를 몸소 이해하게 유도하는)이 없는지 아쉽기만 했다.

Foundations Of JSP Design Patterns (Paperback) - 10점
Patzer, Andrew/Springer-Verlag New York Inc

사실 이런 방식은 KSUG 세미나의 전신인 이프릴세미나 때, 일민형이 기획하고 내가 발표한 스프링 테스트 전략에서도 써먹었던 방법이고, 그 이후 다양한 강의에서 활용했다. 특히 토비의 스프링 3 1장에 펼쳐진 코드 진화 과정은 장고의 시간을 거쳐 진화시킨 내용이라고 할 수 있다. 책 한 권에서 쓰이고 말기엔 아까운 내용이라 교재로 만들기로 했고, 초안은 블로그를 통해 공유하기로 했고, 일민 형도 허락했다.

셋째, 토론에 대한 기대다. 블로그를 보는 즐거움 측면에서는 2006년 맹목적으로 스프링을 증오하던 댓글러(?)가 활약하던 시절이 즐거웠다. 엠파스가 사라져 흔적이 없어졌지만, 내 블로그에서 일민형과 와스추종자가 주고받던 댓글 전쟁을 그야말로 흥미진진했다. KSUG 그룹스에서 일부 토론이 이어지지만, 블로그 공간에서는 찾아보기 어려운데 17주 동안만이라도 글 타래가 이어지길 기대한다. 혹시라도 토론이 벌어진다면 가장 마음에 드는 글을 골라 '2010년 영회인포 베스트마우스상'을 이벤트를 방금 생각해냈다. 도전 하시라! (물론 공정성 따윈 없이 내 맘대로 시상한다.)

시작도 안 했는데 글이 꽤 길다. 원피스에서 잘 써먹는 방법대로 볼만할 때 다음 시간을 기약해야겠다.


소프트웨어에 미치지 못하는 하드웨어(?)
목적만 딸랑 이야기하고 마치기 아쉬우니 본론을 꺼내기 전에 맥스님의 독중감에 의견 보태는 글로 마무리해야겠다. 말을 꺼내기 전에 일민 형 마음을 상하게 할 수도 있는 내용임에도 연거푸 책의 겉모습에 대한 불만을 토로하는 이유는 분명히 하려고 한다. 나는 이 책의 내용에 대해 더 할 수 없는 극찬을 하고 싶은 사람이다. 아마 영문으로 출간했으면 아마존에서 상당한 판매량을 올렸으리라고 확신한다. 그래서 내용과 비교하면 고민이 부족한 외형이 불만스럽다. 심지어 해당 출판사에 계신 분도 모두 지인이고, 노력하는 모습을 멀리서나마 치켜봤음에도 눈 감아 줄 만한 내용은 아니다. 미래를 위해 쓴소리를 마다할 순 없다. 전에 외형에 대해 이야기할 때 출판사 부사장님은 종이질에 대한 투자를 이야기하셨고, 출판 경험에서 나온 독자의 평균적인 요구사항에 대한 확신을 말씀하셨다. 하지만, 내 생각은 다르다. 물론, 출판 문외한이니 대단한 의견이랄 순 없다. 1장을 지하철에서 읽기 위해 긴 고민 없이 바로 칼로 1장을 뜯는 모습은 일반적이라고 할 순 없다. 그런 면에서 맥스님의 생생한 글을 보니 낯선 땅에서 동지를 찾은 듯해 기뻤다. 생생한 표현력을 느끼시라고 발췌해본다.

책의 외형적 특징 때문에, 지하철에서 책읽는 나의 관습(수도권 생활자로 하루 4시간 가까이 지하철에서 보냄)에 맞질 않아서 그렇다. 책의 순서상 회사에서 읽을만한, 레퍼런스형식도 아니여서, 틈틈히 집에서만 읽는데, 휴일은 가족과 보대다 보니, 더욱 진도가 더디다. 사실 틈틈히 읽는다는 것도 그 '외형적 특징' 때문에 쉽게 집어들기도 힘들다. 느워서 보기도 힘들어 책상이나, 식탁에서 펼쳐 보는데, 좀 궁색맞기도 하다. 용기내어 쇼파에 누워서 펼쳐보기도 했지만, 내 배가 감당하기 힘들어 한다. 어쨌든, 이런식으로 조금씩 읽어 나가고 있다. 1)은 저자가 초장에 언급했지만, 느낌으로 전달받을려면, 좀 시간이 지나봐야 알겠다. 그러나 소문대로, 읽는것은 마치 소설읽는것 처럼 잘 읽힌다. 그래도 외형적 특징인 두꺼움은 여전하다.

출처: 토비의 스프링3 :: 독중감(1) - 느낌

최근 내가 만난 토비의 스프링 3 독자 사례를 더 들어 본다.
  • SI 회사에서 프레임워크 관련 일을 하는 K모 과장님을 만났다. 토비의 스프링 3 샀냐고 물었더니, 책을 집으로 배송했더니 회사로 가져올 엄두가 나지 않아 아직 읽지는 못했다고 답했다.
  • 우리 팀 직원 C군. 1장 읽고 토론하자고 했는데, 집에 책이 있어서 빈손으로 왔다. 차마 책을 안 가져왔느냐고 나무랄 수가 없었다.
  • 함께 토론했던 P씨. 토론하자고 만난 자리인데 역시 빈손으로 왔다. 모두 공감하리라는 표정으로 들고 올 엄두가 나지 않았다고 말했다.
  • 우리 팀 직원 P씨. 한 손에 노트북을, 한 손에 토비의 스프링 3을 들고 나가는데 비가 왔다. 토론 장소로 이동하는 거리가 꽤 멀었다. 하마터면 버릴 뻔했다고 농담을 했다.
  • 구글 채팅으로 J님과 대화를 했다. 금요일 퇴근이라 토비의 스프링 3을 집에 들고 오는데 비 때문에 책이 다 젖었다고 한다. 보통 책은 가방에 넣지만, 배낭을 매는 일이 드문 회사원은 토비의 스프링 3을 가방에 넣기 어렵다.

출판사의 판단과 달리 분량 자체에 불만을 느끼는 사람은 아직 찾지 못했다. 토비의 스프링 3은 기존 서적과 독자층이 다르다. 물론, 판매만 놓고 보면 다른 유형의 독자 혹은 구매자까지 폭넓게 고려해야 하지만, 적어도 토비의 스프링 3 독자를 제대로 이해했다면, 기존 틀을 벗어나려는 시도를 해봤으리라 생각하기에 겉모습에 진한 아쉬움이 남는다.

1장을 뜯어서 봤더니 낱장으로 분리된다. 남은 내용은 제본가게에 맡기라는 충고를 들었는데, 좋은 방법인 듯하다.


2010.9.20 추가

컴퓨터 서적으로 해서 양장본은 좀 ... 그래요. 프레임워크 파트별로 해서 3권정도로 분리할 수 있게 했음 어땠을까하고 생각합니다....) 2010-07-16 21:54:49
출처: http://ihoney.pe.kr/tag/%EB%82%98%EB%8A%94
 


설정

트랙백

댓글

토비의 스프링 3 A/S

2010 2010/07/28 09:00
아직 출간 전이지만 집필은 끝난 상태로 못 다한 이야기를 벌써 후기로 적었군요. 욕심쟁이..



토비의 스프링 3 - 10점
이일민 지음/에이콘출판

설정

트랙백

댓글

토비의 스프링 3 - 10점
이일민 지음/에이콘출판


역시 술김에 사심 가득한 홍보성 글을 올립니다. 사랑(?)하는 토비 형이 지난 일년간 연 수입의 9/10를 손해 보면서 화끈하게 투자한 책이 다음 달에 나오네요. 앞으로 다시는 저술이나 번역을 안하겠다고 할 만큼 심혈을 기울인 책입니다. 화공과 출신이라 그런지 몰라도 1장은 조금 지루하지만 로드 존슨(Rod Johnson)도 한글을 안다면 인정할만한 책이 아닌가 합니다. 물론, 지금 술김이지만, 추천합니다.


특히나 DI(Dependency Injection) 설명을 위한 초난감 DAO 개선 절차는 이 책의 꽃입니다. 물론, 실무 수준에서는 2부의 엑기스 중심 정리가 더욱 도움이 되겠지만 말이죠... 쩝... 암튼 형 대단해. 2006년 일면식도 없는데 까칠하게 블로그에 태클 단 일 이해해줄께. 다음에 서울 오면 오룡해삼 쏴~






설정

트랙백

댓글

얼마전 부산대 석사분들과 이야기할 기회가 있었다. Hibernate 공부를 하고 싶은데 변변한 국내서가 없어 어렵게 Hibernate in action을 읽는다고 했다. 국내서로 Hibernate 책을 하나 본 듯 한데 자세히 살펴본 것은 아니지만, 어떻게 사용하는지 사례 같은 인상이었다. Hibernate와 마찬가지로 Spring의 경우도 국내에서 활발하게 쓰인 것은 그리 오래되지 않았다. 반면에 다행히도 저서와 역서가 좀 있는 편이다. 최근에 2.5 관련 서적이 나왔고, 판매부수가 꽤 높다고 한다. 하지만, 구성이 레퍼런스와 유사해 실무에 응용에 관한 이야기는 많지 않았던 듯 하다. 그래서, Spring 버전 차이가 꽤 있음에도 불구하고 여전히 Spring 프레임워크 워크북을 보는 분들이 꽤 많다.

Spring 프레임워크 워크북
박재성 지음/한빛미디어

스프링은 역서도 꽤 있다. 가장 두꺼운 책으로 기억하는데 Spring in action 역서도 있다. 최근에 2판이 나왔는데 회사 동료가 공동역자로 참여해 현재 리뷰중이다. Spring in action 역시 레퍼런스 스타일이라 실무 적용과는 괴리가 좀 있다. 개인적으로 Spring in action을 통해 가장 큰 도움을 받았던 부분은 Acegi 개념을 이해할 때 였다. Spring in action은 스프링 레퍼런스보다는 개념 설명이 좋다. 그림도 많고, 설명이 간결하다. 반면 실무 적용에 참고할 용도로는 Pro Spring이 좋다. 이 책은 개념 설명보다는 활용법 측면이 강하다.

2.5를 다루고 있지는 않지만, 스프링을 이해하는데는 여전히 로드 존슨의 빨간책 세 권이 최고라는 점은 많은 사람이 동의할 것이다. 아쉽게도 역서는 없거나 부실하다. 1권만 역서가 있는데, 번역 시점 상 책 내용을 이해할만한 사람이 드물 시점에서 무리하게 번역을 시도한 것이 아닌가 하는 짐작이 간다. 특정 페이지만 읽었던 기억이 있는데 역자가 내용을 이해하지 못했다는 인상을 받았다. 로드 존슨의 세 권은 마지막 서적은 주로 사용법 관점이고, 첫 책은 설계 철학을 이야기하고 있다. 세 권 중에 가장 마음에 드는 2권 without EJB는 양자를 적절히 다뤘다. 하지만, 이 세 권은 꽤나 어렵다.

현실은 이러한데, 토비형이 나름 심혈을 기울여서 스프링 책을 쓰고 있다. Agile Spring이라고, 전에 소개한 바 있는 Agile Java 에서 이름을 따왔다고 한다. 기획안을 들어보니 3부로 구성했는데, 1부는 점차 진화하는 형태로 코드를 따라가면서 스프링 설계 철학을 다룬다고 한다. 2부는 전반적인 스프링 기능 소개를 하고, 마지막 3부는 아키텍처에 대한 이야기를 담고 싶다고 한다. 흥행을 떠나 스프링 사용자라면 흥미를 가질 수 밖에 없는 구성이다. 수십권의 책은 물론이고, 오랜 ACM 논문까지 뒤척이며 집필 삼매경에 빠졌다고 한다. 즐거운 마음으로 책을 쓰고 있다는 점이 출간하는 서적에 기대를 갖게 만든다. 오는 9월말을 목표로 기획하고 있는 세미나에서 책 내용을 일부 공개하자고 제안을 했다. 토비형도 흥미로워했는데, 세미나에 대한 구체적인 계획이 나오지 않아서 자세히 언급은 못하겠다.

설정

트랙백

댓글