달력

10

« 2017/10 »

  • 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
  •  
  •  
  •  
  •  
사람들이 Lisp을 처음 배울 때 Clojure를 선택하기 어렵게 만드는 요인들이 뭐가 있을까요? 일단 '상태를 변화시키는 게 번거롭다. 불가능하진 않은데, 뭔가 귀찮다.'라는 것도 하나가 되겠죠. 상태 변화를 지양하는 게 바람직하긴 하지만, 그게 너무 불편해 언어 배우는 거 자체가 싫어진다면, 방법은 있습니다. 아래와 같은 variable 함수를 짜면 되겠죠.

(defn variable [& initial-value]
  (let [value (atom (or nil (first initial-value)))]
    (fn [& keyword-and-new-value]
      (if (empty? keyword-and-new-value)
        (deref value)
        (let [keyword (first keyword-and-new-value)
               new-value (second keyword-and-new-value)]
          (cond (= keyword :=) (reset! value new-value)
                    (= keyword :value) (deref value)))))))

이 함수를 이용하면, let이나 def로 정의한 변수의 값을 '간편하게' 변경할 수 있습니다. 다음 테스트케이스를 보시죠. let에 대한 예이지만 def에도 동일하게 사용하시면 됩니다.

(deftest variable-test
  (let [x (variable)
         y (variable 3)
         z (variable {:a 1 :b 2})]
    (is (nil? (x)))
    (is (= 3 (y)))
    (is (= 3 (y :value)))
    (is (= 4 (y := 4)))
    (is (= 4 (y)))
    (is (= 5 (y := (+ 1 (y)))))
    (is (= 5 (y)))
    (is (= {:a 1 :b 2} (z)))
    (is (= {:a 1 :b 2 :c 3} (z := (assoc (z) :c 3))))
    (is (= {:a 1 :b 2 :c 3} (z)))
    (is (= {:a 1 :b 2 :c 3} (z :value)))))

사용법은 아래와 같습니다.
(def x (variable)) ; x를 변경 가능한 값으로 만듭니다.
(def x (variable 3)) ; x를 초기값이 3인, 변경 가능한 값으로 만듭니다.
(x) ; x의 값을 리턴합니다. 위와 같이 설정했다면 3이 되겠죠.
(x :value) ; 역시 x의 값을 리턴합니다. (x)와 똑같은 기능을 합니다. 다만 (x)와 같이 쓸 경우, 가독성이 안 좋은 경우가 있어, :value란 값을 넘기면 값을 리턴하도록 만들어 놓은 것입니다. 취향대로 쓰시면 됩니다.
(x := 4) ; :=는 값을 설정하는데 사용합니다. 왼쪽과 같이 하면 x의 값은 4가 되겠죠.


또 장애가 되는 게 뭐가 있을까요? 객체 지향 언어가 아니라는 게 마음에 걸리시나요? Common Lisp 객체 지향 시스템의 핵심이 어떤 거라고 생각하시나요? 바로 '멀티메서드'입니다. (Common Lisp의 Object System은 일반적으로 사람들이 생각하는 것과 조금 다릅니다.) 그리고 Clojure 역시 멀티메서드 시스템을 가지고 있죠. dispatch 함수와 derive를 통해, type을 정하고, type 사이의 관계를 정의하는 것도 가능하구요. 따라서 객체 지향 시스템이 추구하는 '다형성'은 기본적으로 가능합니다. 그럼 뭐만 있으면 될까요? inheritance만 있으면 되겠죠.(사실 폴 그레이엄의 글을 보면 알 수 있듯이 객체 지향 시스템이 갖춰야 하는 요건이 무엇인지는 약간 애매한 문제입니다. encapsulation 같은 부분도 좀 그렇지만.. encapsulation의 한 방법으로는 closure를 사용할 수 있겠죠.) 이 부분은 그리 어렵지 않으니 스스로 한 번 해보시기 바랍니다.

아니면, Lisp의 장기를 살려, 객체 지향 시스템을 만들어 볼 수도 있겠죠. 아래 제가 Smalltalk의 시스템을 본따서 Clojure로 만든 객체 지향 시스템을 첨부합니다. 사실 예전에 올렸던, ANSI Common Lisp 책의 예제를 Clojure로 구현한 객체 지향 시스템은 여러가지 문제가 있었습니다. 메시지를 보낼 때마다 tell을 호출해야 하니, 순식간에 코드는 tell로 뒤덮이게 될 것이고, 이래서야 도저히 실제로 사용할 수가 없겠죠. 그 밖에도 인스턴스 변수 값을 변경할 수 없고, 클래스 변수와 예약어 'super'가 없으며, 객체들이 메서드를 따로 가지고 있어서 공간 낭비가 크다는 단점도 있었습니다. 이번에 짠 코드는 이런 단점들을 모두 개선했습니다. 사용법의 예는 아래와 같이 (object :message & arguments ...)와 같은 문법을 따릅니다. Smalltalk에서는 모든 클래스가 Object에 subclass 메시지를 보내서 만들어지기 때문에, 아래와 같이 클래스를 선언하게 됩니다. (Object가 java.lang.Object를 가리키고 있기 때문에, 이 라이브러리에서는 모두 대문자인 OBJECT로 이름을 붙였습니다.)

(def Rectangle
        (OBJECT :subclass
            {:class 'Rectangle
            :instance-variable-names [:width :height]
            :area (fn [] (* (self :width) (self :height)))}))

(let [rectangle (Rectangle :new {:width 20 :height 30})]
      (rectangle :area))
=> 600

예약어 super는 self와 똑같이 사용하시면 됩니다. 보시다시피 모든 inheritance는 :subclass 메시지를 통해 이루어지구요. 자세한 사용법은 유닛테스트를 참조하시면 좋을 것 같습니다.                   



저작자 표시 비영리 변경 금지
신고
Posted by chanwoo
2010.09.18 23:42

Premortem 분류없음2010.09.18 23:42

소프트웨어 마에스트로 과정 중, 김창준 멘토님께 premortem이라는 기법을 배우게 되었습니다. 이 기법은 삶이나 또는 프로젝트에서 있을 수 있는 위험을 미리 예측해서, 위험 완화 계획을 세우는 데 도움이 될 수 있는 기법입니다.

간단한 실험을 통해 이 기법이 유효하다는 걸 알 수 있었는데요, 멘토님께서 저희 그룹을 두 조로 나눈 뒤, 한 조에는 ’교수님께서 내년 여름에 한 달 동안 유럽 여행을 다녀오실 것이다. 여행 계획을 되도록 상세하게 세워봐라.’라고 미션을 주셨구요, 다른 조에는 ’교수님게서 작년 여름에 한 달 동안 유럽 여행을 다녀오셨다. 여행 과정이 어땠는지 되도록 상세하게 기술해봐라.’라고 미션을 주셨답니다. 두 조는 다른 조에 어떤 미션이 주어졌는지 몰랐구요. 결과는 어땠을까요? 계획을 세운 팀은 비교적 추상적이고 성근 계획이 나왔던 반면에, 후자쪽은 구체적인 이야기들이 많이 나왔답니다. 제가 연구실에서 회식을 하면서 연구실 사람들을 상대로 실험을 해 봤는데, 역시나 같은 결과가 나와서 굉장히 재밌더라구요. 이 결과에 따르면 사람은 미래보다 과거의 일을 생각할 때 더욱 구체적인 그림을 그릴 수 있는 것 같아요. 그럼 이런 결과를 어디에 써먹을 수 있을까요?

프로젝트의 시작에 앞서 ’프로젝트를 실패로 몰고 갈 수 있는 위험들을 예측해보자.’라고 회의를 하는 게 아니라, ‘여러분은 1년 후의 이 자리에 있습니다. 이미 프로젝트는 처절하게 실패했고, 여러분은 좌절을 느끼고 있습니다. 도대체 프로젝트가 실패하기까지 무슨 일이 있었던 걸까요?’라고 묻는다면 보다 구체적인 실패의 원인이나 시나리오들을 끌어낼 수 있으리라는 거죠. 그리고 이미 프로젝트가 실패했다는 가정을 깔고 회의를 진행하기 때문에, 실패의 가능성이나 원인에 대해 말하는 것을, ‘우리의 희망적이고 원대한 프로젝트에 감히 부정적인 실패의 가능성을 언급해?’와 같은 식으로 받아들이는 것을 막을 수 있게 됩니다. ^^

얘기를 나눌 때 하나 주의할 점은, 각자가 생각한 실패의 원인이나 시나리오들을 자신만 볼 수 있게 기록해 두었다가 모두가 한꺼번에(한번에) 얘기하는 것이 좋다는 것입니다. 브레인스토밍 식으로 얘기하게 되면, 다른 사람이 하는 얘기를 듣고 '아 정말 그럴 수 있겠구나'하고 깊이 공감이 가는 나머지, 다른 얘기가 생각이 안 나고 자꾸 그 쪽으로만 생각이 쏠릴 수 있기 때문이죠. 이러면 상상력을 제한하게 됩니다.

이렇게 회의를 해서, 여러 가지 실패 시나리오와 원인들이 나오게 되면, 회의에 참여한 사람들이 투표를 하게 됩니다. 자기가 생각하기에 이건 정말 일어날 수 있으리라고 생각하는 부분에 ’중요' 표시를 붙이게 되는거죠. 한 사람이 붙일 수 있는 ’중요' 표시는 정하기 나름이겠지만, 저희 때는 3개로 했답니다. 하나가 너무 중요하다고 생각되면 한 항목에 2개를 붙일 수도 있구요.

이렇게 해서, 뽑아낸 위험 항목들을 가지고, 이런 위험들을 어떻게 완화할까 논의를 할 수 있겠죠. 결국 premortem이란, 사람들이 생각하는 시점을 옮겨서, 마치 과거를 보듯 미래를 예측하게 해 주는 기법입니다.
저작자 표시 비영리 변경 금지
신고
Posted by chanwoo
2010.09.01 00:15

XP와 CMMI에 대한 생각 분류없음2010.09.01 00:15

대학원에 들어와서 처음으로 접했던 프로세스 개선 방법론은 CMMI 였다. 그 후로 XP second edition을 테스트 주도 개발이나 리팩토링과 같은 책들과 함께 읽게 되었고, 여러가지를 느꼈던 것 같다. XP나 CMMI를 진득하게 경험해 보지도 못하고 그것들에 관한 글을 쓴다는 것이 어불성설이긴 하지만, 개인적인 느낌들을 적어보는 것은 상관 없지 않을까 싶다.

XP 에 대한 개인적인 인상은 이렇다. XP 및 agile 개발은 ’변화'에 대항하기 위한 방법론인 것 같다. 생각해 보자. 'agile'이라는 단어는 '기민한'이라는 뜻이다. 주위가 한적한 시골이고, 모든 것이 정적이라면, 내가 기민해야 할 필요가 있을까? 기민하고 순발력 있게 행동하는 것은 주위의 환경이 빠르게 변화할 때나 필요하다. 따라서 우리는 그 이름으로부터, 애자일 개발 방법론이 빠른 변화에 대응하기 위한 것이라고 유추할 수 있다.

좀 더 구체적으로 말한다면, XP의 실행지침들은 ‘변화의 비용’을 낮추기 위한 노력들로 보인다. 소프트웨어 개발 초기에는 의사 결정의 근거로 삼을 ’정보'의 양이 절대적으로 부족하다. 정보의 양이 늘어나는 것은 개발이 진행되고 많은 탐색이 이루어지고 난 뒤이다. 따라서 정보의 양이 늘어난 뒤에 의사 결정을 하는 것이 유리하다. 하지만 소프트웨어 공학 분야의 실험 결과는 개발 단계의 뒤쪽으로 갈수록 무엇인가를 변경하는 데 드는 비용이 기하급수적으로 늘어난다고 지적하고 있다. 찰흙이 굳어진 뒤에는 형태를 변경시키는 데 많은 힘이 드는 것처럼 말이다. 따라서 의사 결정을 뒤로 미루고 싶다면 계속해서 ’말랑말랑한' 상태를 유지해야 하고, 이는 ’변화의 비용’을 가급적 낮게 유지한다는 것을 의미한다. XP의 실천방법이나 원리들은 대부분 여기에 초점을 맞추고 있는 것으로 보인다. 

‘점진적 설계'는 위에서 설명한 내용들을 대표하는 실행지침이라고 할 수 있다. 실제로 XP 책의 점진적 설계 파트에는 다음과 같은 문구가 나온다. ‘XP 팀은 소프트웨어를 변경하는 비용이 속수무책으로 상승하지 않는 조건들을 만들기 위해 열심히 노력한다. 자동화된 테스트, 지속적인 설계 개선의 실천, 명시적인 사회적 절차 등이 모두 변경 비용을 낮게 유지하는 데 기여한다.’
즉, 무작정 설계를 뒤로 미룰 수는 없으며 의사 결정을 뒤로 미루기 위해서는 변경 비용을 낮추려는 노력을 부단히 해야 한다는 것이다.
<이는 마치 JIT(Just In Time)과도 흡사하다. JIT에서 재고 부족으로 인해 물건을 팔지 못해 생기는 손실은 ’암초'에, 그리고 재고 수량은 ’수심'으로 종종 비유되곤 한다. JIT를 따라한다고 무작정 ’재고'를 줄이면(수심을 낮추면) 배는 암초에 부딪혀 파손되고 만다. JIT의 핵심은 수심을 낮추는(재고를 없애는) 동시에 암초를 깎는(제품 공급 시간을 단축하는) 것이다. 그래야만 배가 암초에 부딪혀 파손되지 않을테니까. 마찬가지로 XP를 무작정 따라하다가 배가 파손되는 경우를 당하지 않으려면 암초를 깎아내는(변화에 따른 비용을 낮추는) 노력을 부단히 해야 할 것이다.>


다른 지침들도 살펴보자. ‘테스트 주도 프로그래밍’을 통해 유닛 테스트 셋을 유지하는 이유가 무엇인가? 여러 가지가 있겠지만 나중에 가해질 어떤 변화가 기존의 기능을 깨뜨리지 않는지 확인할 수 있기 때문이다. 어떤 변화가 문제를 일으키지 않는다고 확신할 수 있을 때, 변화를 시도하기는 조금 더 쉬워지고, 변화의 비용은 감소한다.


리팩토링 역시 변화의 비용을 낮추는 행위다. 리팩토링은 코드 가독성을 높이고, 중복되는 코드를 줄이며, 코드 사이의 의존성을 낮추는 방향으로 디자인을 향상시킨다. 가독성이 높은 코드가 이해하기 쉽고, 이해를 해야 코드를 변경할 수 있으니, 코드 가독성을 높이는 것은 변경을 쉽게 만든다. 또한 코드 중복과 코드 사이의 의존성을 줄이게 되면 변경이 전파되는 것을 막을 수 있으니, 변경 비용이 줄어든다. <코드 가독성 얘기가 나온김에 잠깐 다른 얘기를 해보자. '조엘 온 소프트웨어'를 보면, 코드를 이해하기 쉽게 한답시고 변수명을 길게 작성하는 사람은 풋내기 프로그래머라는 얘기가 나온다. Lisp 쪽의 문화는 어떨까? 폴 그레이엄이 Lisp 진영 전체를 대표한다고 볼 수는 없겠지만, 그 역시 terse한(짧고 간단한) 변수명을 선호한다. 반면에, 스몰토크 진영을 보자. 스몰토크에서는 '약어를 일체 쓰지 않는다.' 짧은 변수명으로 인해 절약되는 타이핑 시간보다, 나중에 코드를 보게 될 사람들이 겪을 이해의 어려움이 훨씬 큰 댓가라고 보기 때문이다. 조엘의 논리대로라면 스몰토커 전체는 풋내기 프로그래머일게다. 하지만 내 경우에는 스몰토크쪽의 손을 들어주고 싶다.>

YAGNI(당신은 그것이 필요없을 것이다.)라고 말하는 이유가 무엇일까? 변화가 생길 것이기 때문에, 당신은 미래에 무엇이 필요하리라고 예측할 수 없다는 것이다. 정보의 양이 적은 오늘이 아니라 정보의 양이 많아지는 내일로 의사 결정을 미루라는 것이다. 미리 많은 것을 준비해 놓았다가 변화 때문에 그것이 모두 ’낭비'로 계산된다면, 결국 변화에 따른 비용을 크게 지불하는 꼴이 된다.

XP에서 ’고객 참여’나 ’커뮤니케이션'을 그토록 강조하는 이유가 무엇일까? Conway의 법칙에 의하면 소프트웨어의 아키텍처는 집단 구조 내지는 커뮤니케이션 구조와 일치하게 되어 있다. 소프트웨어 아키텍처의 변동이 없을 거라면 집단을 아키텍처 형태로 편성하고, 부서 사이의 커뮤니케이션 통로만 가느다랗게 열어 놓아도 상관 없을 것이다. 하지만 소프트웨어 구조의 변화를 예상한다면, 커뮤니케이션 형태를 특정 구조로 한정해서는 안 될 것이다.
<변화의 비용을 낮추기 위한 요소 중 가장 중요한 것 하나만을 꼽으라면, '커뮤니케이션'을 꼽을 것 같다. 다음 비유를 생각해 보자. 고체나 금속은 분자들이 주위 분자들과만 결합하기 때문에 그 형태가 고정된다. 하지만 액체의 경우는 분자들이 부유하며 분자간 인력에 의해 결합하고 떨어지기를 반복하기 때문에,동적이다. 조직이 유연하기 위해서는 커뮤니케이션 형태가 고정되서는 안 된다는 것을 연상시키는 이미지라고나 할까? 스크럼 회의, 프로젝트 진행 상황 게시판, 짝 프로그래밍, 코드 공유, 고객 참여, 유닛 테스트 셋에 의한 문서화, 코드가 스스로를 말하게 한다는 스몰토크의 문화 등등은 모두 커뮤니케이션의 양 뿐 아니라 질을 높이며, 커뮤니케이션의 형태를 유연하게 하려는 노력이라고 생각된다.>

XP에서 ’함께 앉기’를 통해 bus number를 높이려는 이유는 무엇일까? bus number가 낮으면 인적 자원 변화로 생기는 타격이 크기 때문이다.

왜 ‘아기 발걸음'으로 걸어야 하나? 방향이 자주 바뀔 것이기 때문에, 크게 내딛으면 손해라서이다.


사실 소프트웨어 개발이 ‘변화'라는 용과 싸우는 일이라는 것은 비즈니스 쪽의 needs와 무관하지 않다고 본다. (변화에 적응하지 못하는 기업은 살아남지 못한다라는 메시지를 주는) ‘누가 내 치즈를 옮겼을까?’와 같은 책이 유행한 이유가 무엇이라고 생각하는가? 학부 때 경영학을 복수 전공하면서 마르고 닳도록 들었던 얘기는 변화의 속도는 점점 빨라지고 있고 기업은 그 변화에 적응해야 한다는 것이다. 유연성을 극대화하기 위한 매트릭스 조직 같은 게 나오는 것도 그런 이유다. 소프트웨어 개발은 비즈니스 쪽의 needs를 해결하기 위한 것이고, 비즈니스 쪽이 극심하게 변화한다면 소프트웨어 쪽 역시 극심한 변화의 요구에 시달리는 것은 당연한 결과다. XP가 각광을 받는 것은 이런 상황에서 변화에 효과적으로 대응할 수 있는 방법론이기 때문이 아닐까?

CMMI 에 대해서도 몇 자 적어보자면, CMMI는 프로세스 자체가 아니라, 프로세스 ’개선을 위한’ 방법론이다. 국내에서 많은 폐단을 불러일으키는 형식주의로만 인식되고 있는 것이 안타깝긴 하지만, CMMI를 프로세스 개선을 위한 본래 목적으로 사용한다면 나쁘지 않은 것이라고 본다. CMMI의 핵심은 ’좋은 프로세스들의 핵심 특성들을 모아 놓은 것’이기 때문이다. 예를 들어 성숙도 레벨 2의 목표 중 ’제품의 형상 관리를 하는 것이 좋다’라는 부분이 있고, 자신이 속해 있는 회사가 버전 관리 시스템을 사용하고 있지 않다면, 소스 코드의 형상 관리를 어떻게 하는 게 좋을지 구체적인 대안들을 탐색해 볼 수 있을 것이다. CMMI는 이런 식으로 프로세스 개선을 위한 요소들을 알려줄 뿐 구체적인 방법을 제시하지는 않는다. 심지어 그 방법이 XP의 실천방법 중 하나가 될 수도 있을 것이다. 많은 사람들이 생각하는 것 같이 CMMI와 XP가 ’상극'인 것은 아니다. 둘은 추상화 수준과 기술하고 있는 부분이 다르기 때문에, 둘을 상극이라고 하는 것은 ’사과의 반대는 바나나다’라고 하는 것과 같다.
저작자 표시 비영리 변경 금지
신고
Posted by chanwoo


티스토리 툴바