소프트웨어 분야에서 유연성은 다양한 요구사항을 수용할 수 있는 소프트웨어의 구조적 특성이라고 정의할 수 있다. 소프트웨어는 다른 어떤 컴퓨팅 요소보다도 유연하다. 그리고 잘 만들어진 소프트웨어일 수록 더 유연하게 요구사항을 수용할 수 있다. 소프트웨어의 적용 분야가 확대되고, 소프트웨어 개발 업체들 간에 경쟁이 치열해지고, 더 많은 사람들이 소프트웨어를 사용하게 되고, 더 많은 기기들이 연결되고 더 많은 정보를 수집하게 되면서 유연성에 대한 요구는 점점 더 증가하고 있다. 이러한 요구사항을 반영하기 위해서 소프트웨어는 유연성을 다른 어느 요소보다도 높은 가치로 가지고 갈 수 밖에 없다. 이것이 현대에 객체지향 언어가 대두된 이유이다.

그렇다면 객체지향 언어는 어떤 방식으로 더욱 유연한 구조를 가질 수 있게 되었을까? 여기에 대한 답 역시 현실에서 찾아볼 수 있다.


어린 왕자의 유연성 : 양이 든 상자

소프트웨어의 유연성을 떠올리면 항상 어린 왕자의 일화가 떠오른다. 어린 왕자는 사막에 불시착한 조종사(화자)에게 양을 그려줄 것을 부탁한다. 조종사는 양을 그려본 적이 없기 때문에 거친 솜씨로 이런 저런 양을 그려 준다. 하지만 어린 왕자는 어떤 것은 병들어 보인다, 어떤 것은 숫양이다, 어떤 것은 너무 늙어 보인다는 이유로 퇴짜를 놓는다. 그러면서도 계속해서 양을 다시 그려달라고 말한다.(이쯤에서는 까다로운 요구사항을 늘어놓는 고객이 떠오르게 된다.) 그러자 조종사는 아무렇게나 쓱쓱 그린 상자를 주면서 네가 갖고 싶어하는 양은 그 안에 들어 있다고 말한다. 그러자 어린 왕자의 얼굴은 환하게 밝아진다. 어린 왕자가 어떤 양을 상상하든 그 양은 그 상자 안에 들어 있다. 그래서 어린 왕자는 상자에 만족하게 된다.

우리가 현실세계에서 말하는 유연성이란 이런 상자와도 같다. 구체적인 사항들을 세세하게 늘어 놓으면 정확하긴 해도 다른 것으로 대체하기는 힘들다. 좀 엉성하고 덜 구체적인 것은 이리저리 가져다 붙이면 이것도 되고 저것도 된다. 어린 왕자의 상자는 그런 엉성하고 덜 구체적인 것의 결정판 정도라고 할 수 있다. 엄밀히 말해서 상자는 양과는 너무 동떨어져 있다고 생각될 정도로 매우 추상적이다. 하지만 그렇기 때문에 어린 왕자는 그 상자에서 자신이 원하는 양의 모습을 마음껏 상상해 볼 수 있었다.

이와 비슷한 예를 하나 더 들어보자. 수잔 서덜랜드는 그의 저서 "밈"에서 다음과 같은 타로 카드 점괘를 이야기 한다.

"당신은 남들의 애정과 인정을 받아야만 하는 타입이면서도 스스로에 대해서는 엄격하네요. 겉으로는 절도 있고 자신을 잘 통제하는 것처럼 보이지만, 속으로는 걱정이 많고 불안감도 많이 느끼고요. 가끔은 내가 제대로 된 결정을 내렸을까 하고 심각하게 고민하는군요......"

이 점괘는 사실 트릭인데 이는 "바넘 효과"라는 것을 이용한 것이다. 바넘 효과는 거의 누구나 스스로에 대해서는 참이라고 생각하지만 남에 대해서는 그렇게 생각하지 않는 진술을 던지는 것이다. 이것은 심리적인 유연성에 해당한다. 즉, 대부분의 사람들이 자신에게 맞다고 생각하는 점괘를 말해 줌으로써 그 점괘를 믿도록 만든다. 이러한 점괘에서는 당연히 매우 구체적인 날짜나 시간, 구체적인 명칭이나 사건들에 대해서는 언급을 피하는 것이 상책이다. 그래야만 더 많은 사람들에게 들어 맞는 유연한 점괘가 될 것이기 때문이다.


율리우스 카이사르의 유연성 : 추천 편지


율리우스 카이사르는 기원전 1세기에 살았던 로마의 지도자이다. 율리우스 카이사르는 인물 사전에 보면 로마의 정치가, 장군, 작가라고 나온다. 대단히 다재다능한 사람으로써 생애 전체가 유연성의 표본이 아닌가 싶기도 하다. 그가 지휘해서 이긴 전투들은 대부분 너무 독창적이어서 안타깝게도 사관학교 교재로 쓰이지 못할 정도이고(사관학교에서 교육을 하려면 어느 정도 정형화되고 누가 하더라도 같은 효과를 낼 수 있는 전투 방식이어야 하는데 카이사르의 그것은 너무나도 창의적이었다는 의미이다.), 이런 능력은 여자를 홀리는데도 사용되어 유명한 난봉꾼으로 통하기도 했다.

어쨌든 카이사르의 이러한 재능의 원천은 철저히 합리적인 방식을 통해서 얻어진 것으로 생각된다. 그는 발명에도 일가견이 있었는데, 긴 두루마리에 글을 적고 읽었던 당시에 종이를 낱장으로 잘라 한쪽 면을 이어 붙이는 "책"을 발명하였다. 이것은 두루마리가 이전에 글을 읽었던 위치를 알기에는 적합하지만 원하는 글이 적힌 임의의 위치를 빠르게 찾는데는 불편하다는 점에 착안한 것이다. 또한 당시까지 사용되던 부정확한 로마력을 대신하여 율리우스력이라는 당시로서는 매우 정확한 달력을 사용하도록 했다. 이 달력은 기원전 1세기에 사용되기 시작한 이후로 1582년 그레고리력으로 바뀌기 전까지 사용될 정도로 매우 정확했다.

이런 합리적인 사고 방식은 그가 권력을 유지하기 위해서 지방의 선거에 자신이 원하는 인물들을 추천한 방식에도 나타난다. 카이사르는 다음과 같은 문장이 쓰인 편지들을 미리 만들어 두었다.

"카이사르는 선거구 (       )의 유권자 여러분이 던지는 표로써 후보자 (     )가 그들이 바라는 관직에 당선될 수 있기를 희망한다."

그리고 필요한 시기에 이 편지에다 선거구 이름과 후보자 이름만 적어 넣음으로써 필요한 모든 선거구에서 자신이 원하는 후보를 지지해 주도록 추천할 수 있었다. 카이사르의 합리적인 성격 덕분에 매우 유연성 있는 추천 편지가 만들어지게 된 것이다.

이러한 유연성의 예는 현대에도 자주 찾아 볼 수 있다. 이 글을 읽고 있는 사람들 중에서 이미 결혼을 한 사람이 있다면 결혼을 위해서 청첩장을 만들어 전달했을 것이다. 그리고 그 청첩장의 내용은 그 청첩장을 받는 사람들마다 모두 달랐을 것이다...... 라고 짐작한다면 아무래도 유연성이 떨어진 생각이 아닐 수 없다. 거의 모든 사람들은 청첩장의 내용물은 모두 같고, 단지 전달할 상대에 따라서 겉포장에 이름만 다르게 적어 보냈을 것이다. 이것이 인간미는 조금 떨어질지 모르지만 바쁜 현대인들에게는 상당히 합리적인 선택이라고 할 수 있다.


어린왕자의 상자, 유연한 점괘, 카이사르의 추천 편지, 청첩장의 예를 통해서 우리가 현실 세계에서 유연성이라는 것을 어떻게 이용하고 있는지 확인해 볼 수 있었다. 일단 여러 요구사항들(어린왕자가 원하는 그 양, 점을 보러 오는 다양한 사람들, 다양한 선거구에 다양한 후보)을 모두 만족시키려면 모든 요구사항이 포함하는 공통된 부분들을 먼저 알아야 한다. 그러기 위해서 서로 다른 점들을 제거하고 공통된 부분을 모아 필요한 대상을 미리 만들어 둔다. 그리고 나서 개별적인 요구사항들에 대해서는 차이점만 조금씩 더해서 대응한다. 이렇게 함으로써 여러 요구사항을 개별적으로 대응하는데 들어가는 수고를 최대한 덜어낼 수 있다. 요컨데 똑같이 할 수 있는 부분을 뽑아 내어 한번만 하고 다른 부분들에 대해서는 최소한으로 대응하는 방식이다.


유연성 확보 전략 : 오케스트라의 비유

이제 조금 더 객체지향에 가까운 유연성 비유를 이야기 해보도록 하겠다. 이번에는 오케스트라에 비유해 보도록 하겠다. 오케스트라는 매우 다양한 악기를 연주하는 연주자들과 지휘자가 함께 음악을 연주한다. 악기는 바이올린, 피아노, 플루트, 하프, 비올라, 바순, 트럼펫, 트럼본, 첼로, 콘트라베 등 매우 다양하다.


이제 우리는 오케스트라 지휘자의 행동을 유추해 보자. 일반적으로 지휘자는 특별히 말을 하지 않고 지휘봉을 이용하겠지만 목적한 바를 명확하게 보여주기 위해서 지휘자가 말로 지휘를 한다고 생각해 보겠다. 지휘자는 이제 연주가 시작되었으면 좋겠다고 생각한다. 그래서 이제 각각의 연주자들에게 연주를 부탁해야 한다. 이 상황에서 지휘자가 이렇게 이야기한다.

"바이올린 연주하세요. 피아노 연주하세요. 플루트 연주하세요. 하프 연주하세요......"

이렇게 각각의 연주자들에게 개별적으로 연주를 부탁한다면 어떻게 되겠는가? 일단 연주를 시작하는 시점이 다르기 때문에 아름다운 연주가 되지도 않을 뿐더러 연주를 다 시작하게 될 때까지 시간이 매우 많이 걸리게 될 것이다. 이것은 일반적이고 합리적인 방식이라고 할 수 없다.

그러면 이제 다음의 방법을 생각해 보자.


이런 난감한? 상황을 타개하기 위해서 지휘자는 기지를 발휘한다. 지휘자는 각각의 악기를 다루는 사람들을 한꺼번에 다룰 수 있는 방법을 모색한다. 바이올린을 연주하는 연주자, 피아노를 연주하는 연주자, 플루트를 연주하는 연주자...... 이들은 모두 다른 악기를 연주하지만 연주자라는 공통점을 가지고 있다. 따라서 각각의 악기 이름으로 대응하기 보다는 공통된 부분, 즉 연주자라는 호칭으로 연주를 부탁하면 된다.

"연주자 여러분, 연주하세요."

이렇게 되면 각 연주자들은 동시에 연주를 시작할 수 있고, 지휘자는 단 한번만 요청하면 모든 악기가 연주 되도록 할 수 있다.

이 과정에서 지휘자는 매우 구체적인 대상, 즉 바이올린 연주자, 피아노 연주자 등을 대신하여 조금은 추상적인 대상, 즉 연주자라는 개념을 만들고 활용하였다. 이는 앞서 살펴본 현실 세계의 예들을 대표하는 방식이다. 실제적이면서 개별적인 대상 대신에 공통적이고 조금은 추상적인 개념을 대상화하고 이를 이용함으로써 개별적으로 대응하는 방식에 비해 훨씬 합리적이고 손쉽게 요청을 전달할 수 있었다.


우리는 이제 현실 세계에서 서로 다른 다양한 요구사항들을 어떤 방식으로 합리적이고 유연하게 대처하는지를 알게 되었다. 여러가지 요구사항들을 수집(각 악기 연주자들)하고, 구체적인 요구사항에 비해 다소 추상적인 공통점(연주자)을 찾아내고, 이를 대상화(연주자라고 부를 수 있도록)하고, 이들 공통점에 차이점을 조금 더하고(어떤 연주자는 바이올린을 연주한다), 공통점을 중심으로 대상을 다룬다(연주자 여러분 연주하세요). 이런 방식으로 유연성을 확보하는 것은 조금만 관심있게 찾아보면 늘상 있는 있는 일이라는 점도 알 수 있다. 동사무소에 준비된 각종 서류들은 이름과 서명란, 주소 등의 몇가지 구체적인 정보만 놔 둔체 이미 작성되어 있다. 여기에 자기의 정보만 적어 넣으면 곧바로 훌륭한 신청서가 된다. 보험을 가입할 때에도 약관은 이미 작성되어 있고, 가입자가 개인 정보를 기록하고 사인만 하면 가입이 완료된다. 이런 예를 더 찾아보자면 무수히 많을 것이다.

그러면 이제 우리가 현실 세계에서 유연성을 확보하는 과정을 단계별로 살펴볼 시간이다.


공통점을 추출한다.( = 차이점을 감춘다.)

현실 세계에는 마치 아날로그와도 같은 수준의 서로 다른 요구사항들이 있다. 아날로그 수준이라는 말은 요구사항이 하나하나 떨어져 있지 않고 서로 연속적으로 이어진 것처럼 다양하다는 의미이다. 연속적으로 이어진 요구사항들은 그 사이사이에 또 무수히 많고 다양한 요구사항들을 품고 있다. 이렇게 생각해야 하는 이유는 이미 밝혀진 요구사항들보다도 더 많은 요구사항이 앞으로 생겨날 수 있기 때문이다. 사람들은 종종 한가지를 보면 다른 한 가지를 떠올린다. 요구사항 하나는 그와 유사한 생각을 만들어 내고 이것은 다시 구체적인 요구사항이 되어 돌아오기도 한다. 소프트웨어 분야에서 유독 웹 개발자들이 힘들어지는 이유가 바로 이것 때문이다. 소프트웨어 시스템 내부가 어떻게 동작하는지는 쉽게 알 수 없지만 브라우저 상에서 표현되는 그림이나 글자는 쉽게 눈에 보이고, 눈에 보이는 순간 생각을 하게 되고, 생각이 다시 요구사항으로 돌아 오면서 이미 만들어 놓은 것을 고치게 하기 때문이다.

공통점을 추출하는 과정은 이 아날로그 수준의 서로 다른 요구사항들을 모두 수용할 수 있는 공통된 특징을 모으는 과정이다. 이 과정은 당연히 서로 다른 부분은 제거한다. 오케스트라의 비유에서 각 악기 연주자들은 서로 다른 악기를 가지고 있다. 서로 다른 악기를 가지고 있다는 점을 포함하고 있으면 모든 연주자들을 지칭할 수 있는 공통점을 만들어 낼 수 없다. 따라서 개별적인 악기들은 공통점에서 제거한다.

이와 함께 제거 되어야 하는 것은 또 있다. 각 악기 연주자들은 서로 다른 개인이기도 하다. 거주하는 곳이 다르고, 식성이 다르고, 평소 즐겨 입는 옷도 다르다. 이름, 전화번호, 주민번호, 나이, 헤어스타일 등 다른 점을 찾아보자면 무수하게 많다. 또 공통점도 있을 수 있다. 모두다 한국 사람일 수도 있고, 모두 다 악보를 볼 두 눈을 가지고 있을 수 있다. 이렇게 나열하다 보면 공통점과 차이점은 무수하게 많아지게 될 것이다. 그래서 공통점만 모으는 과정에서 너무 많은 공통점이 모일 수 있다. 그렇기 때문에 공통점을 추출하는 과정에서는 목적에 맞지 않는 불필요한 공통점은 제거되어야 한다. 오케스트라 지휘자는 현실 세계에서 연주자들과 친하게 지내기 위해서 이런 저런 정보들을 알아야 할 수도 있다. 하지만 지금은 지휘에 집중해야 할 때이다. 따라서 지휘하는데 꼭 필요한 공통점만을 추출해 내면 된다. 국적이나 악보를 볼 수 있는 눈 따위는 이 기준에 의해서 제거 되어야 한다.

이처럼 차이점들을 제거하고, 공통된 부분들 중에서 우리의 목적과 상관이 없는 정보들 역시 제거되고 나면 이제 공통점만 모은 어떤 것이 된다.


"대상화" 한다.

어떤 공통점이 모였을까? 우리는 연주를 할 것이기 때문에 각 악기 연주자들은 연주를 할 수 있어야 한다. 그리고 필요한 시점에 연주를 멈춰 줄 줄도 알아야 한다. 더 많은 공통점이 필요할 수도 있지만 이 정도만 모였다고 가정하자. 

그러면 이제 "대상화"를 할 시간이다. 대상화란 모아 놓은 공통점을 다룰 수 있게 만드는 과정이다.


(이상화)

  내가 그의 이름을 불러주기 전에는 
  그는 다만 
  하나의 몸짓에 지나지 않았다


 
내가 그의 이름을 불러주었을 때 
  그는 나에게로 와서 
  꽃이 되었다

  ......
 
 
우리들은 모두 
  무엇이 되고 싶다

 
나는 너에게 너는 나에게 
  잊혀지지 않는 하나의 의미가 되고 싶다
.


이 대상화를 떠올리면 항상 이상화 시인의 꽃이라는 시가 떠오른다. 이 시의 아름다움도 좋지만 대상화라는 과정이 어떤 것인지를 이해하는데도 도움이 된다. 우리가 어떤 대상에 대한 개념을 모았다고 하자. 하지만 이것에 정확한 명칭을 부여하여 다룰 수 있도록 만들기 전에는 그것은 "하나의 몸짓"에 지나지 않는다. 하지만 공통점들을 명료하게 만들고 명칭을 부여하면 그것은 "꽃"이 된다. 오케스트라의 비유에서 "꽃"은 바로 "연주자"라는 개념이다. 이 연주자라는 개념은 구체적이지 않고 추상적인 개념이다. 따라서 구체적인 대상을 현실 세계에서 찾을 수는 없다. 하지만 반대로 연주자라는 개념을 다룰 수는 있다. 연주자는 연주를 할 수 있어야 해, 연주자는 필요할 때 연주를 멈출 수 있어야 해 와 같은 방식으로 다소 추상적인 방식이긴 하지만 다룰 수 있는 대상이다. "대상화"의 개념을 명쾌하게 이해하지 못하겠다면 일단 "명칭"을 부여했다는 정도만이라도 이해하면 되겠다.


차이점을 더한다.

이제 남은 것은 차이점이다. 차이점은 공통점을 추출하는 과정에서 남은 것들이다. 그렇다고 남은 모든 것들은 아니다. 우리의 목적은 오케스트라를 지휘하는 것이다. 차이점을 더하는 과정도 목적에 맞는 것에만 해당한다. 여기서 각 악기 연주자들의 개인정보나 취향은 제거된다. 대신 오케스트라의 목적에 맞게 악기는 다들 가지고 있어야 하겠다. 오케스트라 지휘에 앞서 필요한 악기들이 모두 준비 되었는지를 확인하는 과정도 필요할 것이다. 따라서 차이점에는 악기가 포함된다. 이제 우리는 연주자라는 개념에 개별적인 차이점이 더해진 개별적인 악기 연주자를 설정한다. 대략 플루트 연주자, 하프 연주자, 피아노 연주자 등이 되겠다.

이 차이점을 더하여 개별적인 악기 연주자를 만드는 과정은 한가지 암시적인 가정을 포함한다. 플루트 연주자는 매우 구체적이다. 하지만 동시에 좀 더 추상적인 개념인 연주자와 동일시 될 수도 있다. 즉 플루트 연주자는 다른 연주자들과 구분되는 플루트라는 악기 속성을 가지면서도 동시에 연주자가 가진 연주하는 속성, 연주를 멈추는 속성도 가지고 있어야 한다. 이렇게 되어야만 다음 단계가 가능해진다.

현실에서라면 이와 같은 과정을 겪어야 할 것이다. 아래는 지휘자가 플루트 연주자에게 하는 가상의 대화이다.

"플루트 연주자님, 플루트 연주자님은 다른 악기 연주자들과 다르게 플루트를 가지고 계셔야 합니다. 그리고 저는 연주를 효율적으로 하기 위해서 플루트 연주자님을 그냥 연주자라고 부를 것입니다. 연주자란 연주하세요 하면 자기가 가진 악기를 연주하고, 멈추세요 하면 연주를 멈추는 사람입니다. 이해되셨죠?"

현실 세계에서는 이미 각 악기 연주자가 연주자 개념을 알고 있기 때문에 이런 일이 일어나진 않는다.


공통점을 통해 대상을 다룬다.

이제 지휘자가 오케스트라 지휘를 시작할 시점이다. 앞서의 지휘자와 플루트 연주자와의 대화와 유사한 대화들이 각 악기 연주자들과도 오고 갔다고 가정하자. 그러면 이제 지휘자는 연주를 시작할 수 있는 상태가 된 것이다. 각 악기 연주자들은 우리가 정의한 "연주자"의 개념을 알고 있다. 따라서 각 악기 연주자들에게 개별적으로 연주를 부탁하지 않아도 된다. 단지 다음과 같이 말하기만 하면 된다.

"연주자 여러분, 연주하세요"

그러면 플루트 연주자는 자기가 가진 악기인 플루트를, 하프 연주자는 하프를, 피아노 연주자는 피아노를 연주하게 될 것이다. 이렇게 열심히 공통점을 대상화하고 이용할 수 있도록 만들어 놓고서도 각각의 악기 연주자에게 일일이 연주를 지시하는 것은 비 합리적인 일이다.


자 이제 현실세계에서의 유연성이라는 것은 무엇이고, 이것이 수많은 요구사항들을 어떻게 수용하는지 알 수 있게 되었으며, 유연성을 확보하는 전략을 단계별로 이해할 수 있게 되었을 것이다. 이제 현실 세계에서의 유연성 확보 방법이 우리가 알고자 하는 객체지향 언어와 어떻게 연관되는지 살펴볼 차례다.

Posted by 이세영2
,

현실과 소프트웨어 세계에서의 객체

우리는 현실에서는 객체의 세계, 소프트웨어 세계에서는 객체지향의 세계에서 살고 있다고 해도 과언이 아니다.

현실에서의 객체란 독립적이면서 (분리되지 않고) 하나로 취급되는 인식의 단위를 말한다. 인간은 대상을 정확히 인식하기 위해서 목적한 대상과 다른 대상들과의 개념적인 차이들을 필요로 하고, 그 차이들이 명확해지고 나면 그 대상에 대해 명칭을 부여한다. 이 과정을 통해 불분명했던 대상은 정확한 명칭을 지닌 객체가 된다. 우리의 인식 속에서 일단 객체로 자리잡은 대상은 고유한 인식적 위치를 점유하게 되고 이는 다른 대상을 판별하는데 이용됨으로써 인식의 세계가 점점 더 넓어지는데 일조하게 된다. 대상을 다른 대상들과 분리하여 인식하는 이와 같은 방식은 현실에서의 인간이 살아가는데 큰 도움을 준다.

근본적으로 프로그래밍 언어로서의 객체지향 개념은 위에서 본 현실에서의 객체에 대한 인식과 크게 다르지 않다. 프로그래밍 언어의 세계는 관념적인 세계이다. 인간은 현실을 객체 단위로 이해하고 있지만 실제 세계는 객체적인 세계가 아니다. 개와 고양이는 (관념적으로는) 같은 동물이긴 하지만 개와 고양이는 같은 개념으로 묶을 수 있는 단위가 아니다. 하지만 우리의 두뇌는 현실을 관념적으로 파악하기 때문에 거리낌 없이 개와 고양이를 묶어 동물이라고 부른다. 그리고 아이러니하게도 이렇게 비현실적인 관념으로 세계를 파악하는 방식이 전체를 분리하지 않은 체 이해하는 방식보다 거의 언제나 더 유용하다. 유용하다는 말은 더 빠르고 정확하게 이해할 수 있다는 말이다. 따라서 프로그래밍 언어에 객체지향이라는 개념이 도입된 이유는 인간이 객체를 중심으로 프로그래밍을 하는 편이 더 빠르고 정확하게 이해하면서 구현하는 것이 가능하기 때문이다. 이 점은 매우 중요한데, 프로그래밍의 도구는 오직 두뇌 뿐이고, 두뇌가 더 빠르고 정확하게 문제를 이해하는 것은 프로그래밍에 그만큼 유리하게 작용하기 때문이다.

2016년 6월 기준으로 Java, C++, Python, C#, PHP, Javascript, Ruby, Objective-C 등과 같이 굵직한 언어들 중에서 객체지향을 온전히, 혹은 상당 부분 지원하는 언어의 비중을 따져보면 약 44.5%를 차지했다. 만약 하드웨어적인 제약 사항을 만족시키기 위한 언어(C, Assembly)나 제한된 목적을 위한 언어(Cobol, Matlab, Delphi, Visual Basic 등)를 제외한다면 범용적이고 일반적인 어플리케이션의 대부분은 객체지향 언어로 만들어진다고 볼 수 있을 것이다.


프로그래밍 언어의 역사와 객체지향

우리가 현실 세계를 객체로 이해하고 있다는 점을 이해한다면 객체지향 언어가 프로그래밍 언어 영역에 도입된 시기는 매우 빨랐을 것으로 추측할 수 있다. 실제로도 그렇다. 이반 서덜랜드(1938~)는 1963년도에 "스케치패드 : 사람과 기계와의 그래픽 대화 시스템"이라는 논문을 통해 객체지향 개념을 기반으로 구현한 그래픽 프로그램을 발표한다.("누가 소프트웨어의 심장을 만들었는가") 이후 시뮬라67 언어가 만들어지고(1967), 앨런 케이에 의해 스몰 토크라는 언어가 만들어짐으로써 온전한 객체지향 언어가 탄생하게 된다. 시기적으로 보면 현대에 가장 많이 사용되고 있는 비 객체지향 언어인 C 언어가 1972년에 만들어졌으니 객체지향 언어는 완성된 비 객체지향 언어보다도 개념적으로 더 오랜 역사를 가지고 있는 셈이다.

하지만 이율배반적이게도 많은 사람들이 객체지향 언어를 접한 시기는 상대적으로 최근의 일이다. 여기에는 여러가지 이유가 있다. 첫째 객체지향 언어는 컴퓨팅 파워가 뒤쳐졌던 70년대에는 다른 언어들에 비해 상대적으로 비인기 언어였다. 낮은 하드웨어 성능을 최대한 끌어낼 수 있는 절차지향 언어가 먼저 인기를 끌었다. 둘째, 우리에게는 객체를 중심으로 현실을 이해하는 것 만큼 익숙한 이해의 방식이 하나 더 있기 때문이다. 이것은 어떤 문제(또는 일)를 시간과 인과 관계의 순서로 이해하는 방식이다. "처음엔 A였다가 B라는 이유로 C가 되었다가 결국엔 D로 끝났어"와 같은 서술 방식은 시간과 공간 속에서 살아가는 인간에게 매우 익숙한 상황 인식 및 설명의 방식이다. 이러한 방식을 프로그래밍 언어에 도입한 것이 절차지향 언어이다. 첫번째 이유로 인해 기피되던 객체지향 프로그래밍 방식이 초반부터 매우 강력한 경쟁자를 만난 셈이다.

세번째 이유는 객체지향 언어를 이해하는 것이 절차지향 언어에 비해 상대적으로 어렵다는 점이다. 객체를 중심으로 이해하는 것이 현실을 이해하는데 유용하다는 점에서 볼 때는 매우 아이러니한 일이 아닐 수 없다. 우리는 매우 자연스럽게 세계를 객체 중심으로 이해한다. 이 과정은 너무나도 자연스럽기 때문에 그 메커니즘에 대해서는 잘 인지하지 못한다. 우리는 개와 고양이를 개와 고양이라고 부르면서 구분하고 있고, 동시에 동물이라는 카테고리 안에 이 둘을 자연스럽게 포함시킨다. 또 동물과 식물을 구분하고 있으면서 동시에 생물이라는 카테고리 안에 이 둘을 포함시킨다. 이것을 그림으로 그리면 트리 구조가 될 것이다. 하지만 우리는 이러한 구분을 트리 구조를 통해서 이해하고 있지 않다. 그냥 자연스럽게 그 인식 과정을 받아들인다. 하지만 이러한 메커니즘을 모사하여 프로그래밍 언어에 도입하는 과정은 그다지 순탄하지 않다. 개와 고양이를 구분하려면 개를 개념적으로 명확하게 정의하고 고양이를 개념적으로 명확하게 정의할 수 있어야 한다. 그리고 이들 둘을 동물이라는 같은 개념으로 묶을 수 있으려면 두 동물이 가진 개념 중에서 공통점을 추출할 수 있어야 한다. 또한 동물의 특성을 개와 고양이가 가질 수 있게 하려면 상속이라는 개념을 도입해야 하고, 동물이라는 개념으로 개와 고양이를 다룰 수 있으려면 다형성이라는 개념을 도입해야 한다. 요컨데 인간의 두뇌가 현실을 이해하는데는 엄밀한 정의도 필요하지 않고, 전체적인 논리적 완결성을 추구할 필요가 없지만 이를 매우 논리적인 완결성을 요구하는 프로그래밍 언어에 도입하는 데에는 다양한 개념의 정립이 필요하다.


객체지향이 대두된 이유

그렇다면 절차지향 언어가 계속 우위에 설 수도 있었을텐데 객체지향 언어는 왜 다시 대두되었고, 현재와 같은 주류 언어가 될 수 있었을까?

기초적이고 단편적인 이유들을 먼저 설명해 보자. 첫째로 컴퓨터의 연산 능력이 좋아졌다는 점이다. 객체지향 언어가 생겨난 70년대 이후 수십년에 걸쳐 하드웨어는 비약적인 발전을 거듭해 왔다. 그리고 하드웨어적/소프트웨어적 발전으로 인하여 하드웨어는 단일한 플랫폼을 넘어서 병렬화되면서 성능은 더더욱 좋아지게 되었다. 이것은 상대적으로 연산량을 많이 필요로 하는 객체지향 언어가 활동할 수 있게 된 배경이 된다. 둘째로 절차지향 언어의 한계점이 대두되었기 때문이다. 앞서 말했듯이 절차지향 언어는 시간과 공간 상에서의 인과 관계를 중심으로 현실을 이해하는 인간의 인식 방식을 모방한 것이기 때문에 이해하기 쉽고 다루기 쉬운 프로그래밍 언어이다. 하지만 절차지향 언어로 개발된 소프트웨어는 어느 일부분을 떼어 내어 다른 소프트웨어를 만드는 것이 어렵다. 절차지향 언어가 함수라는 독립된 단위로 소프트웨어를 분할하고 있지만 각 함수는 연쇄적으로 호출되면서 동작하기 때문에 어떤 부분만을 별도로 나누어 다른 시스템에 적용시키기가 어렵다. 또한 절차 전체에서 메모리를 공유하거나, 특정 절차가 어떤 데이터와 연관되는지를 쉽게 알 수 없기 때문에 전체 동작을 이해하기 위해서는 각 절차들의 내부를 자주 들여다 봐야 되고, 이런 방식으로는 큰 소프트웨어를 작성하기가 어려워진다.

하지만 보다 근본적인 이유는 따로 있다. 1930년대 후반에 소위 "컴퓨터"라는 것이 발명된 직후, 컴퓨터의 용도는 주로 암호 해독이었다. 일련의 덧셈, 뺄셈, 곱셈, 나눗셈 등을 이용하여 인코딩된 정보를 디코딩하는 용도라고 할 수 있다. 1940년대에는 군사 분야쪽으로 용도가 넓어진다. 포탄 궤적용 표, 폭발 계산(원자폭탄 개발), 탄도 미사일 계산과 같이 군사 물리적인 용도가 주를 이루었다. 1950년대에는 FORTRAN 언어가 개발되면서 과학 연구 분야에 컴퓨터가 활용되기 시작한다. 초신성 폭발, 수치해석, 일기예보 등이 그 예이다. 1960년대에는 운영체제와 COBOL 언어가 등장함으로써 고등 제조 기술 분야와 비즈니스 분야에 소프트웨어가 활용된다. 항공기 설계(특히 엔진 설계), 우주선의 제작 및 우주선 궤도 계산 분야, 비즈니스 소프트웨어 분야에 활용되었다. 1970년대에 이르러서는 PC가 출현하고 유저 인터페이스 및 인터넷이 탄생한다. 이와 함께 PC용 소프트웨어가 개발되면서 소프트웨어는 산업 전반에 걸쳐 사용된다. 애플I이 개발된 것이 1976년의 일이다. 1980년대는 PC 시대가 활짝 열리게 된다. MS-DOS가 발명되고(1981), PC의 대중화를 주도한 맥킨토시(1984)가 발명된 것도 이 시기이다. 특히 맥킨토시는 최초의 GUI와 마우스를 채용함으로써 그래픽 기반의 소프트웨어 시대를 열었다. 1990년대는 뭐니뭐니해도 WWW, 즉 월드 와이드 웹의 시대이다. HTML과 웹 브라우저로 인하여 전 세계의 컴퓨터가 서로 정보를 주고 받을 수 있는 세상이 되었다. 이로 인하여 소프트웨어는 닫힌 공간을 위한 용도에서 연결된 공간을 위한 용도로 활용되게 된다. 2000년대는 소셜 네트워크 및 집단 지성의 시대이다. 이 시기에 구글이 기존과는 완전히 다른 개념의 검색 기술을 개발(2003)하였고, Wikipidia(2001)와 같이 집단 지성을 활용하는 시대가 되었다. Facebook(2004)은 SNS의 시대를 열었고, 아이폰(2007)은 이 연결을 통한 가치 창출을 모바일의 영역으로 확대하였다. 2010년대는 빅데이터와 인공지능의 시대이다. IBM은 왓슨(2011)을 통해 빅데이터 기반으로 훈련된 인공지능을 선보였고, 2016년에는 이세돌과 알파고의 대결을 통해 인간의 능력을 넘보는 인공지능의 시대가 시작되었다.

소프트웨어의 역사에서 가장 주목할만한 것은 소프트웨어 활용 영역이 지속적으로 확대 되었다는 점이다. 소프트웨어는 컴퓨터의 초기부터 지금까지 그 적용 분야가 계속 확대되어 왔다. 그러면 이제부터는 그 적용 분야가 점차 축소될 것인가? 인공지능 분야는 현재 제한적인 부분에서만 인간의 능력을 뛰어 넘는 수준에 머물러 있지만 앞으로 적어도 모든 분야에서 인간의 능력을 뛰어넘기 전까지는 계속 발전하게 될 것이다. 이를 위해서는 더 많은 정보가 수집되어 분석되어야 한다. 당연히 데이터는 계속 수집될 것이고, 인간의 능력을 뛰어넘는 분야는 점점 넓어질 것이다. 사람들이 가지고 있는 모든 지식과 컴퓨터 뿐만 아니라 모든 센서가 연결되고 그 데이터가 수집될 때까지 이 과정은 지속될지 모른다. 즉, 소프트웨어는 적용 분야, 크기, 연산량이 확대되는 방향으로 발전해 갈 수 밖에 없다.

이 과정에서 소프트웨어가 갖추어야 할 기능의 필요성, 즉 요구사항의 증가는 필연적이다. 요구사항은 계속 증가한다. 단순히 양만 증가하는게 아니고 적용 분야가 증가하면서 종류도 다양해진다. 또한 소프트웨어와 인간이 만나는 횟수가 증가하면서 요구사항은 점점 더 다양해지고 또 자주 바뀌게 된다. 개별적인 인간의 개성이나 변덕의 수준을 맞추기 위해서는 소프트웨어가 더 많이 바뀌고 더 자주 바뀌고 더 빨리 바뀔 수 있어야 한다. 이렇게 잘 바뀌는 특성, 즉 유연성(flexibility)이 소프트웨어의 최고 덕목이 된다. 그래서 프로그래밍 언어 중에서도 가장 유연성이 뛰어난 객체지향 언어가 새로운 강자로 떠오르게 된 것이다.


소프트웨어가 가져야 할 가치

TDD, xUnit 테스트, 애자일의 창시자로 유명한 소프트웨어 프로그래머 켄트 벡은 "켄트 벡의 구현 패턴"에서 소프트웨어가 가져야 할 가치를 유연성, 단순성, 커뮤니케이션으로 정의하였다. 커뮤니케이션은 갈수록 커져가는 소프트웨어의 규모를 맞추기 위해서는 여러 사람들의 협력이 필요하고, 이를 위해서는 소프트웨어가 자기 스스로를 설명할 수 있는 능력, 즉 커뮤니케이션 도구로서의 기능을 가져야 한다. 또한 사용자의 요구사항은 예측이 불가능하게 변화하거나 추가되기 때문에 소프트웨어는 유연성을 꼭 가져야만 한다. 이들 덕목을 갖추면서도 기능을 구현하는 가장 단순한 방법을 추구하는 단순성을 가지고 있어야 한다.

이들 중에서 소프트웨어의 유연성은 소프트웨어의 존재 이유에 해당하는 가치라고 볼 수 있다. 소프트웨어는 하드웨어와 같은 다른 요소가 감당하지 못하는 기능 변경 요구사항을 수용하기 위해서 만들어진 요소이다. 이로 인하여 소프트웨어의 생애 주기 중 대부분은 수정과 개선 기간이 된다. 로버트 L. 글래스는 (우리가 미처 알지 못한) 소프트웨어 공학의 사실과 오해라는 책을 통해서 소프트웨어의 유지보수가 보통 소프트웨어 비용의 40~80%를 차지한다고 말한다. 이와 함께 60/60 법칙을 제시하는데 소프트웨어 비용의 60%는 유지보수에 사용되고, 유지보수 비용의 60%는 소프트웨어 기능의 개선을 위해 사용된다고 한다. 이는 소프트웨어가 얼마나 자주 변경되는지, 요구사항이 얼마나 자주 바뀌는지를 말해준다. 더불어 유연성이 소프트웨어의 가치 중에서 얼마나 큰 비중을 차지하는지를 알 수 있게 해준다.

객체지향은 소프트웨어의 유연성이라는 측면에서 가장 뛰어난 접근 방식이다. 객체지향 언어는 소프트웨어에 새로운 기능을 추가하거나 기존의 기능을 변경하는 것, 또는 더 이상 필요 없는 기능을 제거하는 유지 보수 작업에 가장 유리한 언어이다. 다음 글에서는 객체지향 언어가 이 유연성을 어떻게 확보하는지를 알아보겠다.

Posted by 이세영2
,

로버트 L.글래스의 우리가 미처 알지 못한 S/W공학의 사실과 오해

간만에 정신이 맑아지고 현실과 미래가 뚜렷히 보이는 명쾌한 작품을 읽은 느낌이다. 왜 이 책이 그렇게 많은 사람들에게 회자되고 인용되었는지 알 수 있었다. 이 책은 소프트웨어가 세상에 등장한 이후부터 이 책이 쓰여진 시점까지 소프트웨어 분야에서 일어났던 모든 일들을 집약한 책이라고 설명할 수 있겠다. 우리가 소프트웨어를 개발하면서 만났던 수많은 일들, 경험적으로는 알고 있었으나 증명하기 어려웠던 문제들, 소프트웨어 개발 과정에서 겪었던 어려움과 그 이유들, 수많은 문제들 중에서 어떤 문제에 집중하는 것이 옳고 어떤 자세로 임해야 하는지 등에 대한 명료한 답을 제시해 준다.

이 글은 이 책(원 제목은 Facts and Fallacies of Software Engineering)에서 얻은 내용들을 정리한 것이다. 하지만 이 글만 읽어보고 책을 읽지 않게 되는 것은 내가 원하는 것과는 정 반대의 일이다. 내가 이 책을 누군가에게 소개한다면 다음과 같을 것이다. 이 책은 소프트웨어 개발과 관련된 모든 사람들이 읽어야 할 책이다. 소프트웨어를 직접 개발하는 사람이라면 꼭 읽어야 할 책이다. 이 책을 모르고 소프트웨어 개발을 해왔던 시간들이 너무 아깝다.


1장  관리

사람

사실 1. 소프트웨어 직업에서 가장 중요한 요소는 프로그래머가 사용하는 도구나 기술이 아니라, 프로그래머의 자질이다.

-       사람이 (소프트웨어 개발) 성공의 열쇠다

-       엄격한 방법론을 적용한 프로젝트를 한꺼풀 벗기고 프로젝트의 성공 이유를 물으면 그 답은 사람이다.

-       소프트웨어 생산성에 있어 가장 중요한 요소는 소프트웨어 실무자 개인의 역량이다.

사실 2 최고의 프로그래머는 최하의 프로그래머보다 28배 뛰어나다.

-       뛰어난 소프트웨어 실무자가 (동료들보다) 5배에서 28배까지 뛰어나다는 사실을 알 수 있다면, 가장 뛰어난 사람들을 잘 돌보는 것이 소프트웨어 관리자의 가장 중요한 업무라는 것은 자명한 일이다.

-       우리의 연구에서 가장 중요한 실질적 발견은 프로그래머 실무 능력의 현저한 개인차다

-       개인간에 5배 정도의 생산성 차이는 흔한 것이다.”

사실 3 지체된 프로젝트에 사람을 추가 투입하면 프로젝트가 더 늦어진다.

-       사람이 많을수록 커뮤니케이션은 더욱 복잡해진다. 따라서 프로젝트가 지연될 때 인력을 투입하면 프로젝트는 더 늦어지는 경향이 있다.

사실 4 작업환경은 생산성과 품질에 지대한 영향을 미친다.

-       프로젝트에서 상위 25%와 하위 25%에 대해서(이들간에는 2.6배 생산성 차이가 났다) 작업환경을 조사한 결과, 상위 그룹은 1.7배 넓은 공간에서 일했고, 충분히 조용한 환경이라고 대답한 비율이 2배 높았고, 개인 공간이라고 말한 비율은 3배 이상 높았으며, 전화를 돌리거나 꺼놓을 수 있다고 답한 비율은 각각 4배와 5배 많았다.


도구와 기술

사실 5 소프트웨어 업계에는 과대선전(도구와 기술에 대한)이 만연해 있다.

-       소프트웨어 기술 각각으로 얻을 수 있는 생산성 향상은 기껏해야 5~35% 정도이다.

-       재사용(공용화)으로 얻을 수 있는 이득도 10~35% 정도이다.

사실 6 새로운 도구와 기술은 도입 초기에 생산성/품질 저하를 초래한다.

-       도구와 기술을 익히는데는 적어도 6개월 ~ 2년 이상이 걸리고, 이 기간동안의 생산성은 기존보다 저하된다.

사실 7 소프트웨어 개발자는 도구에 대해 많은 말을 하지만, 별로 사용하지 않는다.

-       좋은 개발 도구라는 것 중 대다수는 계속 사용되지 않고 폐기된다.

추정

사실 8 폭주하는 프로젝트의 가장 흔한 원인 두 가지 중 하나는 부정확한 추정이다.

-       아직까지 소프트웨어 프로젝트가 걸리는 시간을 추정할 수 있는 정밀한 방법은 없다.

-       다만 분야의 전문가가 하는 추정만이 좀 더 정확할 뿐이다.

사실 9 소프트웨어 추정은 보통 부적절한 시기에 수행된다.

-       소프트웨어 추정은 보통 요구사항이 구체화 되기 전에 이루어진다.

-       많은 프로젝트가 이미 완료 기한이 정해진 상태로 시작된다.

사실 10 소프트웨어 추정은 보통 부적절한 사람들에 의해 수행된다.

-       많은 추정은 경영진이나 마케팅에 의해 결정된다.

사실 11 프로젝트가 진행되면서 소프트웨어 추정을 수정하는 경우는 거의 없다.

-       NASA에서는 소프트웨어 추정 재평가를 주창하며 라이프 사이클 상의 재평가 시점까지 정의한 연구가 있으나 권고를 따르는 사람을 본 적은 없다.

사실 12 소프트웨어 추정이 부정확한 것은 별로 놀라운 일이 아니다. 그러나 우리는 추정이 죽고 산다!

-       일정에 대한 추정이 부적절하다고 해도 프로젝트는 대부분 정해진 일정에 의해 관리된다.

사실 13 경영진과 프로그래머 사이에는 단절이 있다.

-       (경영진이 정한 추정에 맞지 않아) 실패라고 평가된 프로젝트에 대해 기술자의 다수가 가장 성공적인 프로젝트로 평가했다. 애초에 불가능했던 일정과 예산을 포기하고 도전적인 목표를 성공적으로 완료 했다고 생각 했기 때문이다.

사실 14 타당성 조사에 대한 대답은 항상 타당하다이다

-       프로젝트 시작 전에 이루어지는 기술적 타당성(구현 가능성을 검증하는) 조사는 거의 항상 타당하다는 결론을 낸다.

재사용

사실 15 소규모 재사용은 잘 해결된 문제다.

-       소규모 재사용(보통 라이브러리라고 불리는 함수 단위 재사용) 1950년대부터 있어 왔으며 이미 증명된 문제다.

사실 16 대규모 재사용은 여전히 해결되지 않은 어려운 문제다.

-       대규모 재사용(일명 공용화”)은 일반적으로 다양해지는 요구사항에 의해 제대로 활용되기 어렵다.

-       매우 좁은 도메인(예에서는 항공 역학) 내에서는 70%까지 재사용 모듈로 구축될 수 있었다.

사실 17 대규모 재사용은 서로 관련 있는 시스템 사이에서 가장 잘 적용된다.

-       대규모 재사용은 도메인 종속적이다.

-       여러 프로젝트나 여러 도메인에 걸쳐 적용하려 한다면 성공할 가능성이 거의 없다.

사실 18 재사용 가능 컴포넌트는 만들기가 3배 어렵고, 3곳에 적용해봐야 한다.

-       3이라는 숫자는 모두 경험적인 숫자이다. 다만 재사용 가능한 컴포넌트는 일반적인 것보다 만들기가 훨씬 어렵고, 잘 적용되는지를 여러 번 검증해 봐야 한다.

사실 19 재사용된 코드를 수정하는 것은 특히 오류를 범하기 쉽다.

-       기존의 솔루션을 이해하는 것은 소프트웨어 작업 중에서 가장 어려운 일이기 때문에, 재사용을 위해서 기존의 컴포넌트를 수정하는 것은 새로 만드는 것에 비해 매우 어렵다.

-       20~25% 이상을 수정해야 할 경우 처음부터 다시 만드는 것이 더 효율적/효과적이다.

-       소프트웨어 작업은 인류가 지금까지 해온 것 중 가장 복잡한 작업이다.”

사실 20 디자인 패턴 재사용은 코드 재사용 문제에 대한 해결책이다.

-       이 사실은 디자인 패턴과 같은 잘 알려진 설계에 대한 지식이 매우 중요함을 드러낸다.

-       구현된 컴포넌트는 재사용이 어렵지만, 소프트웨어의 구조 및 설계의 재사용은 가능하다.

복잡성

사실 21 문제의 복잡성이 25% 증가하면 솔루션의 복잡성은 100% 증가한다.

-       왜 그렇게 사람이 중요한가? 복잡성을 극복하는 데는 상당한 사고력과 기술이 필요하기 때문이다.

-       왜 대규모 재사용은 성과가 좋지 않을까? (도메인의 차이로 인한) 복잡성이 증대되기 때문이다.

-       왜 코드 리뷰(inspection)가 오류 제거에 대한 가장 효과적, 효율적인 접근 방법인가? 그 모든 복잡성을 걸러내고 오류의 위치를 찾는 데는 결국 사람의 노력이 필요하기 때문이다.

-       기존의 제품을 이해하는 것이 소프트웨어 유지보수에서 가장 중요하고도 어려운 작업인가? 하나의 문제를 해결하는데 적용할 수 있는 접근방법이 매우 많기 때문이다.

-       왜 소프트웨어에는 그렇게 많은 오류가 있는가? 처음부터 소프트웨어를 올바르게 이해하는 것은 매우 어렵기 때문이다.(여기에는 다른 견해가 있다. 소프트웨어는 불완전성의 원리에 지배 받기 때문에 사람의 두뇌가 아니면 오류를 잡아 낼 수 없다. 그리고 그 사람들은 모두 전문가인 것이 아니다. 물론 전문가라고 해서 오류를 만들어 내지 않는 것은 아니지만.)

사실 22 소프트웨어 작업의 80%가 지적인 작업이다. 그 중 상당 부분이 창조적인 작업이다. 사무적인 일은 거의 없다.

-       소프트웨어 실무자가 하는 일에 대한 관찰 연구 결과 80%는 지적인 작업, 20%는 사무적인 작업으로 분류되었다. 이 중 창조적인 작업은 6%에서 29%에 해당한다.

2장  생명 주기

요구사항

사실 23 폭주하는 프로젝트에서 가장 흔한 원인 두 가지 중 하나는 불안정한 요구사항이다.

-       고객과 사용자는 (그리고 대부분의 관리자들도) 보통 어떤 문제를 해결해야 하는지에 대해 확실하게 알지 못한다.

-       프로토타이핑은 요구사항이 명확하지 않을 때 자주 사용한다.(AOM 패턴을 이용해 볼만한 과정이다.)

사실 24 요구사항의 오류는 생산 단계에서 수정하는데 가장 비용이 많이 든다.

(너무 당연한 일이다)

사실 25 누락된 요구사항은 가장 수정하기 힘든 오류다.

-       누락된 요구사항은 이미 만들어졌거나 만들어지고 있는 코드에 대한 설계 수준의 수정을 요구한다.

설계

사실 26 명시적 요구사항을 설계로 옮겨갈 때 파생 요구사항이 폭발적으로 증가한다.

-       (명시적) 요구사항은 실제 어떻게 구현해야 할지를 결정하는 설계 단계에 오면 암시적 요구사항을 파생 시키고, 이 파생 요구사항은 명시적 요구사항의 50배에 달한다.

사실 27 소프트웨어 문제에서 최적의 솔루션이 하나 존재하는 경우는 거의 없다.

-       소프트웨어적인 문제는 문제에 대한 해결책이 매우 많다. 그 중에서 최상의 해결책은 없거나 알아내기가 매우 어렵다.

사실 28 설계는 복잡하고 반복적인 과정이다. 초기 설계 솔루션은 보통 잘못 되었거나, 최적이 아닌 경우가 많다.

-       (이는 애자일 진영의 XP, TDD, 리팩토링과 같은 기술 및 개발 방법론의 정당성에 힘을 실어 준다.)

-       전문 설계자는 설계상 핵심적인 문제에 대해 직접 구현해 보거나 솔루션을 찾아 놓은 다음에야 전체 설계 문제로 넘어간다.(이는 아키텍쳐는 코딩을 해야 한다는 주장을 뒷받침한다.)

코딩

사실 29 설계자의 기본단위와 프로그래머의 기본단위가 일치하는 경우는 거의 없다.

-       설계자의 코딩 경험, 전문 코딩 분야, 역량 등에 의해 설계 기본 단위의 크기가 달라진다. 이와 함께 코딩 실무자 역시 경험, 전문 분야, 역량에 따라 이에 대응되는 기본 단위가 달라지게 된다. 따라서 이 둘이 매칭되기는 어렵다.

-       (이것은 코딩 실무자의 능력이 설계자 수준과 비슷하게 뛰어나야 하고, 설계 수준이 낮거나 설계자가 없을 경우에는 코딩 실무자의 능력이 (설계를 커버할 수 있을 만큼) 매우 뛰어나야 한다는 것을 의미한다.)

-       나는 이 사실 때문에, 설계와 코딩 작업을 분리하는 것은 좋지 않다고 생각한다.”

-       소프트웨어 개발에서 전통적인 작업 분할 방식(설계자, 구현자, 테스터와 같이 전문 담당 업무를 분할하는 방식)은 적절하지 않다.”

사실 30 COBOL은 별로 훌륭한 언어가 아니지만, (비즈니스 데이터 처리에 대해서는) 다른 언어도 마찬가지다.

오류제거

사실 31 오류 제거는 생명주기에서 가장 많은 시간을 소모하는 단계다.

-       일반적으로 요구사항분석(20%) – 설계(20%) – 코딩(20%) – 오류 제거(40%)의 시간을 소모한다.

테스트

사실 32 프로그래머가 완전하게 테스트 했다고 믿는 소프트웨어도 보통은 로직 경로의 55~60%만 테스트 된 경우가 많다.

사실 33 100% 테스트 커버리지도 결코 충분하지 않다.

-       대략 소프트웨어 결함의 35%는 누락된 로직 경로(구현하지 않은 로직)에서, 40%는 로직 경로의 특정 조합을 실행할 때(로직 실행 후 다시 실행할 때 일부 변수가 초기화 되지 않아서 발생하는 오류가 대표적인 예이다) 나타난다. 따라서 100% 커버리지로도 잡히지 않는다.

사실 34 테스트 도구는 꼭 필요하지만, 많은 경우 거의 사용되지 않는다.

-       이유는 테스트 단계 자체가 관심을 많이 받지 못하기 때문이다. 자동화 테스트 도구는 매우 유용하다.

사실 35 특정 테스트 프로세스는 자동화할 수 있고, 또 자동화해야 한다. 그러나 자동화 할 수 없는 테스트 작업도 많다.

-       요구사항 명세서로부터 코드를 자동 생성할 수 있다는 개념은 이미 사라졌다. 따라서 프로그래머 없는 프로그래밍프로그래밍의 자동화에 대한 아이디어 역시 이미 사라졌다.(따라서 코더 개념 역시 사라져야 할 개념이다.)

-       (소프트웨어 개발 단계에서 가장 단순해 보이는) 테스트 조차도 완전히 자동화 할 수 있는 방법은 없다.(사실 모든 소프트웨어 개발 단계 중에서 자동화 할 수 있는 것은 없다.)

사실 36 프로그래머가 작성한 디버그 코드는 테스트 도구에 대한 중요 보완 수단이다.

-       컴파일러 옵션이나 외부 파일을 이용하여 테스트 코드를 실행할 수 있도록 만들어 놓는 것도 테스트에 도움이 된다.(이 책이 쓰여질 당시에는 Unit Test가 널리 보급된 상태가 아니었음을 상기하기 바란다.)

검토와 검사

사실 37 엄격한 검사는 첫 번째 테스트 케이스를 실행시키기도 전에 소프트웨어 제품에 포함된 오류의 90% 까지 제거할 수 있다.

-       (엄격한 검사란 inspection이라는 것으로 우리가 보통 이야기 하는 코드 리뷰이다)

-       (이는 인간의 두뇌만이 소프트웨어를 관리할 수 있는 유일한 도구라는 내 생각을 뒷받침한다)

-       이렇게 좋은 방법임에도 잘 실행되지 않는 것은 오류 검사 단계에 대한 무관심과 엄격한 검사 과정의 어려움(“이미 작성된 코드에 대한 이해가 가장 어려운 것이라는 점을 상기하기 바란다.) 때문이다.

-       (여기에 덧붙이자면 많은 관리자들이 코드리뷰나 페어 프로그래밍을 지적 유희라고 생각하거나 베테랑이 초보자에게 가르치기 위해 하는 일이라고 생각한다. 우리나라의 많은 관리자들은 프로그래밍을 저급한 업무로 취급하면서 모든 개발자가 1~2년쯤 지나면 다들 베테랑이라고 생각하기 때문에 페어 프로그래밍 하려는 사람들을 야단친다.)

사실 38 엄격한 검사도 테스트를 대체할 수는 없다.

사실 39 출시 후 검토(회고라 부르는 사람들도 있다)는 중요하지만, 거의 실행되지 않는다.

사실 40 검토는 기술적 측면과 사회학적 측면을 모두 가지는데, 어느 쪽도 무시하면 안 된다.

-      동료 검토(peer review)에 의해 이성과 감정에 상처를 받지 않도록 해야 한다.

-      비자아적 프로그래밍(코드에 자신의 자존심을 투영하지 않는 것)을 당부하지만 대부분의 개발자들은 자신의 코드에 대해 자부심을 가지려고 한다. (이는 미묘한 문제이면서도 코드를 통한 커뮤니케이션이나 형상 관리를 방해하는 문제이기도 하다. 자신 있는 코드라면 공개하는 것이 마땅하고, 자신 없는 코드라면 공개하고 조언을 받아야 하는 것이 마땅하다. 어느 편이든 코드는 공개되어야 한다.)

사실 41 유지보수는 보통 소프트웨어 비용의 40~80%를 차지한다. 따라서, 유지보수는 소프트웨어 생명주기 중 가장 중요한 단계일 것이다.

-       (일단 다음 절에서 유지 보수란 단순한 오류 수정이 아니라 기능의 개선 및 추가까지 포함한 작업이라는 것을 기억하기 바란다.)

-       유지 보수 비용이 높은 이유는 이미 만들어진 기능을 이해하기가 어렵기 때문이다.

-       (따라서 가독성 높고 간결한 코드를 만드는 것이 개발자의 자질 중 가장 중요한 것이다.)

사실 42 유지보수 비용의 60%는 개선 작업에 소요되는 비용이다.

-       소프트웨어를 처음 개발할 때 고객과 사용자는 새로운 소프트웨어로 무엇을 할 수 있을지에 대해 단지 비전의 일부만 갖고 있을 뿐이다. 소프트웨어가 출시되어 한동안 사용해 본 후에야 사용자는 그 소프트웨어 시스템을 개선해 무엇을 더 할 수 있을지 깨닫기 시작한다.

-       60/60 법칙 : 소프트웨어 비용의 60%는 유지보수에 사용되며, 유지보수 비용의 60%는 개선에 사용된다. 따라서 기존 소프트웨어를 개선하는 것은 큰 일이다.

-       60%는 개선 17%는 오류 수정 18%는 포팅, 5%는 기타 작업

사실 43 유지보수는 문제가 아니라 해결책이다.

(다른 산업 분야와는 달리) 소프트웨어의 유지보수는 대부분 기능의 개선을 위한 것이기 때문에 문제가 아니라 해결책이다. 따라서 부정적으로 보지 않아야 한다.

사실 44 유지보수에서 가장 어려운 작업은 기존 시스템을 이해하는 것이다.

-       유지보수 작업에서 가장 중요한 요소는 이해력이다 –Ned Chapin, 유지보수 분야 개척자-

-       소프트웨어 업무 중에서 가장 어려운 일이 유지보수 작업이다. 보통은 (내가 만든 게 아닌) 다른 사람이 만든 소프트웨어를 다루어야 하기 때문이다.

사실 45 더 좋은 소프트웨어 공학 기술로 개발하면 더 많은(더 적은 게 아니라) 유지보수가 필요하다.

-       현대적 개발 방법론 및 소프트웨어 기술이 적용된 소프트웨어는 더 수정하기 쉽기 때문에 더 많은 수정이 가해지고 더 오랫동안 개선되면서 사용된다.

3장  품질

품질

사실 46 품질은 속성의 집합이다.

-       이식성, 신뢰성, 효율, 사용편의성, 테스트 용이성, 이해 용이성, 수정 용이성

사실 47 품질은 사용자 만족, 요구사항 충족, 비용과 일정 목표 달성, 또는 신뢰성이 아니다.

신뢰성

사실 48 대부분의 프로그래머가 흔히 범하는 오류가 있다.

-       인간은 하나씩 밀린 인덱스, 정의/참조의 불일치, 중요한 설계 항목 누락, 자주 사용하는 변수에 대한 초기화 실패, 일련의 조건 중 하나의 조건 누락 등 특정 종류의 작업에서 쉽게 실수한다.

사실 49 오류는 뭉치는 경향이 있다.

-       오류의 반이 모듈의 15%에서 발견된다.

-       오류의 80%가 단지 모듈의 20% 이내에서 발견된다.

-       대략 80%의 결함이 모듈의 20%에서 나오고, 모듈의 절반 정도는 오류가 없다.

-       특정 모듈이 특히 더 어렵기 때문에, 여러 개발자가 모듈 별로 개발하기 때문에(개인 능력차 때문에) 그럴 것이다.

사실 50 소프트웨어 오류 제거에 있어서 단 하나의 최상의 방법은 없다.

사실 51 오류는 항상 남아 있다. 심각한 오류를 제거하거나 최소화하는 것이 목표가 돼야 한다.

-       오류 없는 소프트웨어를 개발하는 것은 불가능하다.

-       CMM 레벨 4인 팀과 다른 정형방법을 사용하는 팀 둘이서 충분한 비용과 일정에도 불구하고 98% 신뢰성의 간단한 제품을 만들어 내지 못했다.

효율

사실 52 효율은 훌륭한 코딩보다는 훌륭한 설계에 더 많은 영향을 받는다.

사실 53 고급 언어 코드도 어셈블리어 코드의 90%에 가까운 효율을 낼 수 있다.

-       항공 애플리케이션에서 고급 언어의 비효율성(어셈블리 대비 C언어) 10~20% 정도이다.

>  최적화 컴파일러를 이용하면 10% 성능향상

> 튜닝을 통해 2~5% 더 향상 시킬 수 있다.

사실 54 크기와 속도 사이에는 트레이드오프가 있다.

4장  연구

연구

사실 55 많은 연구자들이 연구보다는 옹호에 치중한다.

 

2부 오해 5+5

5장  관리

관리

오해 1 측정할 수 없는 것은 관리할 수 없다.

-       측정할 수 없는 것은 통제할 수 없다는 말은 사실이지만 관리할 수 없다는 말은 아니다. 소프트웨어 설계라는 것은 측정 불가능하지만 관리할 수 있는 대상이다.

-       몇몇 회사에서는 메트릭을 통한 관리를 중요시한다. 그리고 자주 사용하는 소프트웨어 메트릭이 개발되어 사용되고 있다.

-       (우리나라에서 메트릭을 통해 소프트웨어를 관리하지 않는 이유는 관리자들의 소프트웨어에 대한 이해가 부족하고, 필요한 경우 외주를 통해 해결할 수 있는 수준의 저급한 업무로 폄하되고 있기 때문이다. 야구나 농구에서 데이터를 관리하거나 기업의 재무제표가 관리되는 이유와 정반대 이유다.)

오해 2 소프트웨어 품질은 관리로 해결할 수 있다.

-       소프트웨어 품질에는 기술적 요소가 많아 관리만으로 해결할 수는 없다.(이는 소프트웨어를 외주로 개발하는 행위에 대해 경종을 울린다. 자체 기술 부족으로 인하여 기술이 검증된 업체를 통해 개발하고 그 기술을 내제화 하기 위한 외주가 아니라 단지 시간이 부족하거나 허드레 업무라고 생각해서 외주를 주는 경우 관리만으로 품질을 확보하는 것은 불가능하다. 이로 인한 짐은 고스란히 개발자에게 넘겨진다.)

오해 3 프로그래밍은 비자아적이 될 수 있고, 또 되어야 한다.

-       (많은 개발자들은 자신의 코드가 자신의 지적 능력을 대변한다고 생각한다. 그래서 코드에 대해 자아를 투영하곤 한다. 하지만 이러한 자세는 원활한 시스템 통합, 오류 검사, 형상 관리를 방해한다.)

-       오류 없는 프로그램을 작성하는 것은 불가능하다는 것을 인정하고, 기술적 약점이 잘 발견될 수 있도록 열린 자세를 가져야 한다.

도구와 기술

오해 4 도구와 기술 : 한 가지로 모든 문제를 해결할 수 있다.

-       소프트웨어 문제를 해결할 완전한 한가지 기술이나 도구는 없다.

오해 5 소프트웨어 분야에는 더 많은 방법론이 필요하다.

-       많은 방법론이 교수들이나 대학원생 등 소프트웨어 비 실무자들에 의해 개발된다. 특히 엄격한 방법론(융통성을 거부하고 전체 개발 프로세스를 감시하려는 방법론, 예를 들어 전통 waterfall과 같은 방법론)을 경계해야 한다.

추정

오해 6 비용과 일정을 추정하기 위해서는 먼저 LOC(Lines of Code)를 추정해야 한다.

-       LOC 만으로는 부정확한 메트릭이다.(프로그래밍 언어, 도메인, 주석과 같은 요소를 고려해야 한다.)

-       (특히 이 절은 비용과 일정을 추정하기 위해 LOC추정하는 문제에 대해 언급하고 있음을 기억해야 한다. 추정을 위해서 부정확한 메트릭을 사용하는 것에 대한 주의이다.)

-       (LOC는 몇몇 부수적인 메트릭과 함께 사용되면 훌륭하게 기능할 수 있다. 특히 코드의 조건문 빈도, 중복 코드 비율, 모듈 특성 등과 함께 사용한다면 개발자의 생산성을 판단하는데 매우 유용할 수 있다. 같은 모듈이나 계층을 개발하는 개발자들간에도 LOC 10배 이상 차이 나는 경우가 흔하다. 2배 이하라면 큰 의미는 없다.)

6. 생명주기

테스트

오해 7 랜덤 테스트 입력은 테스트를 최적화 하는 좋은 방법이다.

-       소프트웨어의 복잡성이 늘어나면 늘어날수록 랜덤 테스트를 통해 찾아낼 수 있는 오류는 줄어든다.

검토

오해 8 “보는 눈이 많으면, 모든 버그는 그 깊이가 얕다.”

-       오픈소스에 대한 이야기인데, 많은 오픈소스가 다수의 눈을 거쳐 수정되는 과정을 거치지 않고, 수정되는 버그는 대부분 발견하기 용이한 것들이다. 중요하고 심각한 버그들은 여전히 숨어 있을 가능성이 있다.

유지보수

오해 9 과거의 비용 데이터를 살펴봄으로써 미래의 유지보수 비용을 예측할 수 있고 시스템 교체 결정을 내릴 수 있다.

-       다양한 연구가 있으나 (기본적으로 소프트웨어의 유지 보수가 대부분 새로운 기능을 추가하는 일이고, 이것은 이미 매우 어려운 일로 알려져 있으므로) 유지보수 비용을 예측하는 것은 매우 어려운 일이다. 따라서 이를 기반으로 시스템 교체 결정을 내리는 것은 불가능하다.

7장.  교육

테스트

오해 10 프로그래밍을 가르칠 때 프로그램을 어떻게 작성하는지 보여주며 가르친다.

-       잘 만들어진 코드를 읽어 보는 것은 직접 작성하는 것만큼(혹은 그보다 더) 중요하다. 하지만 잘 만들어진 코드 샘플을 찾아 내는 것은 어렵다.

-       다른 사람의 코드를 읽는 것은 소프트웨어 개발에서 가장 어려운 작업을 훈련할 수 있는 일이다.

-       (페어 프로그래밍이나 코드 리뷰에 힘을 실어 주는 사실이다. 다른 사람의 코드를 보지 않거나 고쳐보지 않은 개발자, 잘 만들어진 오픈소스나 라이브러리 코드를 보지 않는 사람의 개발 능력은 언제나 낮기 마련이다.)

Posted by 이세영2
,