What Is Software Design?우리가 소프트웨어 설계란 무엇인가에 대한 그 근원적인 힌트를 찾을 수 있는 좋은 아티클이 있어 번역해 봅니다.
이 글은 1992년 C++저널에 실린 Jack W. Reeves가 작성한 글인데(오래되었지만), 코딩, 테스트, 디버깅도 설계의 한 부분이며, 설계물을 엄격하게 적용해도 제품에 탈없이 적용할 수 없는게 소프트웨어 분야다보니, 그것도 설계, 빌드, 테스트 후 설계하는 과정을 거쳐서 완성품을 만들어야 하니 공학보다는 수공예에 가깝다고 합니다. 그리고 공학의 최종 산출물이 문서이고 이 문서는 코드도 포함되어 있으며, 소프트웨어 개발은 협업으로 진행되다보니 코드의 쓰기와 읽기의 중요성은 아무리 강조해서 지나치지 않는 법이죠. 그리고 소프트웨어 산업은 복잡성이 높은 분야이므로 쉬운 코드(산출물)는 협업의 커뮤니케이션 비용을 줄여주는 효과도 있겠습니다.
다음부터는 기사 전문을 번역한 내용입니다.
특히 C++ 분야의 객체 지향 기술은 소프트웨어 업계를 단번에 사로 잡았다. 그리고 이 새로운 기술의 적용 방법을 설명한 수 많은 기사와 책들이 나타났다. 이는 객체 지향 기술이 단순한 마케팅적으로 과대 광고였는지에 대한 의문은 통증을 최소화하고 이득을 얻는 방법에 대한 의문을 대체해 왔다. 객체 지향 기술이 아직 세상에 나온 지 얼마 되지 않았다는 것을 생각해볼 때 이런 폭발적인 인기는 극히 이례적이라고 말할 수 있다. 왜 객체 지향 기술이 갑자기 인기를 끌게 된 것일까요? 다양한 설명들이 난무했다. 사실, 이유는 단 하나뿐이 아니었을 것이다. 아마도 여러 요인이 합쳐지고 임계점에 도달해 인기를 얻게 된 것이다. 그럼에도 불구하고 최근 소프트웨어 혁명의 중심에는 C++ 그 자체가 있다고 생각된다. 그리고 그 이유도 단 하나가 아니겠지만, 나는 조금 다른 관점에서 답변을 제안하고 싶다: C++의 인기는 소프트웨어 설계와 프로그램을 동시에 쉽게 할 수 있기 때문이다.
이 의견이 이상하게 느껴졌다면 그것은 다분히 내 의도이기도 하지만, 이 아티클에서 제가 말하려고 하는 것은 프로그래밍과 소프트웨어 설계의 관계를 살펴보겠다는 것이다. 거의 10년동안, 소프트웨어 설계를 이루는 일련의 작업과 소프트웨어 설계의 참모습과의 미묘한 차이를 소프트웨어 업계 전체가 놓쳐왔다고 생각한다. 우리가 알 수만 있다면, C++ 인기도의 증가는 우리가 더 뛰어난 소프트웨어 엔지니어가 되기 위해 할 수 있는 중요한 교훈이 숨어 있다고 생각한다. 그 교훈은 프로그래밍은 소프트웨어를 제조하는 것이 아니라, 소프트웨어를 설계하는 것이다.
몇년 전, 내가 참석한 세미나에서 소프트웨어 개발은 공학 분야에 속하는지 여부에 대한 논의가 이루어졌다. 그 당시 토론의 결론은 생각나지 않았지만, 소프트웨어 산업은 매우 유용한 몇가지 유사점을 간과하면서 하드웨어 공학에서의 잘못된 유사점을 창조했다고 내 스스로가 진단했다. 본질적으로, 우리는 소프트웨어 설계라는 것이 진정 무엇인지 모르고 있다는 점에서 소프트웨어 엔지니어가 아니라는 결론에 도달하게 된다. 그리고 그 생각은 오늘 더욱 확고해졌다.
공학 활동의 최종 목표는 몇몇 좋류의 문서이다. 설계 작업이 완료되면 설계 문서가 제조팀에 전달된다. 제조팀은 디자인팀과는 완전히 다른 스킬을 가진 전혀 다른 그룹이다. 그리고 설계 문서가 실제로 완벽하게 설계되어 있는 경우, 제조팀은 제품의 생산을 시작할 수 있다. 즉, 미래에 설계자의 개입없이 해당 제품을 대량 생산할 수 있게 되는 것이다. 나는 자신이 이해하고 있는 소프트웨어 개발 라이프 사이클을 리뷰해 보고, 공학적인 설계 기준을 정말 만족하는 소프트웨어 문서라는 것은 소스 코드 목록뿐이라는 결론에 도달했다.
이 가정에 대해서는 찬반 양론 다양한 의견이 존재할 수 있다. 따라서 본 아티클에서는 진정한 소프트웨어 설계가 최종 소스 코드라고 가정 할 경우, 이 가정에서 도출되는 추론의 일부를 조사하고자 한다. 이 견해(가정의 정당성)가 옳다는 것을 입증할 수 없을지도 모르지만, 이로 인해 C++ 인기에 대한 이유 등 포함해 소프트웨어 업계에서 볼 수 있는 몇가지 사실들을 설명할 기회를 가질수 있기를 바란다.
소스 코드가 소프트웨어 설계의 중요한 결과물로 귀결된다. 이 귀결은 너무 중요하고 자명하지만, 대부분의 소프트웨어 조직에서 맹점이 되고 있다. 그것은 소프트웨어를 제조(빌드)하는 것은 저렴하다는 사실이다. 너무 싸기 때문에 가치를 인정받지 못할수도 있고 저렴해서 무료라고 인식하기도 한다. 소스 코드가 소프트웨어 설계라고 생각하면, 소프트웨어의 실제 제조는 컴파일러와 링커에서 이루어지게 된다. 우리도 소프트웨어 시스템 전체 컴파일및 링크 프로세스를 종종 "빌드하기("doing a build")」라고 부르고 있다. 또한, 소프트웨어 구축용 장비에 대한 자본 투자도 적게 든다. 실제로 필요한 것은 컴퓨터, 편집기, 컴파일러, 링커뿐이다. 한번, 일단 빌드 환경을 이용 가능하게 되면 소프트웨어의 제조에는 약간의 시간만 필요하게 된다. 50,000행의 C++ 프로그램을 컴파일하려면 상당한 시간이 필요할지도 모르지만, 50,000라인의 C++ 코드만큼 복잡한 설계의 하드웨어 시스템을 제조하는 것을 생각하면 덜 오래 걸릴 것이다.
소스 코드가 소프트웨어 설계하다고 생각하면 소프트웨어 설계는 적어도 기계적인 의미에서 비교적 쉽게 만들 수 있다는 추론도 가능하다. 50라인에서 100라인으로 코드로 구성된 일반적인 소프트웨어 모듈을 작성(즉 설계)하려면 대부분의 경우 며칠 걸리지 않는다(완벽하게 디버깅을 완료하는 것은 또 다른 이야기다. 그것은 나중에 살펴보겠다). 이 정도의 복잡성을 가지고 설계를 소프트웨어 수준의 기간내에서 해낼 수 있는 공학 분야가 있는지 물어보고 싶지만, 먼저해야 할 일은 복잡성을 어떻게 측정하는지를 알아내야 할 것이다. 그러나, 소프트웨어 설계는 오히려 급속도로 복잡성이 증가한다는 점이다.
소프트웨어 설계는 비교적 용이하다는 점, 그리고 제조(빌드)는 본질적으로 무료라는 점을 생각하면, 소프트웨어 설계가 엄청나게 거대하고 복잡한 경향이 있다는 것은 당연하다. 이것은 뻔한것처럼 보일지도 모르지만, 종종 문제의 규모가 무시되고 있다. 교육 현장의 프로젝트에서는 기껏해야 수천 줄의 코드 밖에 되지 않지만, 소프트웨어 제품에서 설계자로부터 인도된 시점에서 10,000라인의 설계 산출물이 되기도 한다. 간단한 소프트웨어에서 충분한 이익을 얻는다는 것은 이제 과거의 이야기이다. 이제 일반적인 상용 소프트웨어 제품은 수십만라인의 설계물로 구성되어 있다. 그리고 백만라인대에까지 가는 소프트웨어 설계물도 많다. 게다가, 소프트웨어 설계는 거의 항상 진화한다. 현재 설계에서는 수천 줄의 코드밖에 안될지 모르지만, 그 제품의 일생을 통해 볼 때 그 몇배 더 쓰여질지 모른다.
소프트웨어 설계만큼이나 복잡한 하드웨어 설계가 존재하는 것은 틀림없지만, 여기에서는 현대적인 하드웨어에 대한 두가지 사실에 주목해야 한다. 첫번째는 사실은 복잡한 하드웨어 공학을 적용한 경우 소프트웨어 비평가들이 우리에게 믿게 끔 해 온 만큼, 항상 버그가 없는 상태는 아니라는 것이다. 유명한 마이크로 프로세서가 논리 오류를 가진 상태로 출하된다. 교량과 댐은 붕괴되고, 항공기 추락되고, 수천대의 승용차 및 다른 소비자 제품이 리콜되는 것이다. 이들은 모두 최근 기억속의 것들이며, 모두 설계 오류의 결과물이다. 두번째는 복잡한 하드웨어 설계는 복잡하고 고가의 제조 공정이 필요하다. 결과적으로, 이러한 시스템을 만들어내는 능력이 필요하기 때문에 진정으로 복잡한 하드웨어 디자인을 만들어 낼 수 있는 기업의 수 자체가 한정되어 있다. 그러나, 소프트웨어는 이러한 제약이 적용되지 않는다. 수백개의 소프트웨어 회사가 존재하고 수천개의 매우 복잡한 소프트웨어 시스템이 존재하고 있다. 그리고 그 복잡도와 수는 나날이 증가하고 있다. 즉, 하드웨어 개발자가 배워서 흉내를 내도 소프트웨어 산업의 문제는 그렇게 쉽게 해결할 수 있는 것이 아니다. 하드웨어 설계자는 더 복잡한 설계를 할 수 있도록 도와주는 CAD/CAM 시스템이 있지만, 하드웨어 공학도 소프트웨어 개발처럼 점점 비슷해진다.
소프트웨어를 설계하는 것은 복잡성을 관리하는 작업이다. 이러한 복잡성은 소프트웨어 설계 자체와 기업의 소프트웨어 조직, 그리고 산업 전체에 내포하고 있다. 또한 소프트웨어 설계는 시스템 설계와 매우 비슷하다. 즉, 많은 기술들이 관련되어 있고 종종 하위 분야를 포함할 수도 있다. 따라서 소프트웨어 명세는 유동적이며, 빠르게 그것도 자주 변화하는 경향이 있다. 또, 설계 과정중에 변화하는 경우도 있다. 소프트웨어 개발 팀도 설계 과정 중간에 변경되는 경우가 종종 있기 때문에 유동적이다. 소프트웨어는 하드웨어보다는 여러면에서 복잡한 사회적, 조직적인 유기 시스템과 닮아있다. 이런 모두가 소프트웨어 설계를 어렵게 하고 오류를 쉽게 만들게 한다. 어디에도 그 근원적인 해결책은 없다. 그러나 소프트웨어 혁명이 일어나고 30년 가까이 지난 지금도 소프트웨어 개발은 다른 공학 분야와 비교하면 규율이 없는(쳬계화되지 않은) 예술분야로 생각할 수 있다.
진정한 엔지니어가 설계를 완료하면 그것이 얼마나 복잡하던 간에 기대하는대로 작동한다는 것은 이론의 여지가 없다. 그리고 제조 기술을 이용하여 구축한 것도 잘 동작한다. 이런 일이 일어나기 위해서 하드웨어 엔지니어는 그에 상응하는 시간을 설계 검증과 개선하는데 투입한다. 예를 들어 교량 설계한다고 생각하자. 이러한 설계를 실제로 건설하기 전에 엔지니어는 구조 분석을 실시한다. 컴퓨터 모델을 구축하여 시뮬레이션을 한다. 또한 축소 모형을 만들고 바람의 움직임 등 다양한 방법으로 시험을 진행한다. 짧게 말하면, 설계자는 건설에 앞서 그 디자인이 뛰어난지 여부를 결정하는 데 필요한 모든 생각을 한다. 신형 항공기의 설계는 더욱 힘들다. 이 경우 설계시 예측을 검증하기 위해 실물 크기의 시제품을 제조하고 시험 비행을 실시해야 한다.
많은 사람들의 눈에는 소프트웨어 설계가 하드웨어 설계만큼 엄격하게 공학적으로 진행되지 않아도 된다고 생각한다. 그러나 소스 코드는 설계라고 생각하면 실제로는 소프트웨어 설계자도 자신의 설계에 상응하는 시간을 검증과 개선에 투자를 해야한다는 것을 알 수 있다. 단, 소프트웨어 설계자는 그것을 공학이라고 부르지 않고, 테스팅과 디버깅이라고 부르고 있을뿐이다. 그러나 많은 사람들은 테스팅과 디버깅을 진짜 공학이라고는 생각하지 않는다. 소프트웨어 업계에선 더 그렇게 부르지 않는다. 그 이유는 공학의 본질적 차이보다는 코드가 설계의 과정이라는 점을 소프트웨어 업계가 거부하고 있기 때문이다. 모형(목업), 프로토타입, 모의 실험은 다른 공학 분야에서도 실제로 받아 들여지고 있는 것들이다. 소프트웨어 설계자는 소프트웨어 빌드 사이클의 단순한 경제적 논리때문에 자신의 디자인을 검증하는 공식적인 방법론을 채택하거나 운영하지 않는다.
두 번째 계시: 단지 설계물을 작성하고 테스트할 뿐이라면 무엇보다 저렴하고 쉽게 할 수 있다. 여러번 빌드할 것인가는 고민할 필요도 없다. 이러한 것은 시간이라는 관점에서는 비용이 없으며, 사용한 자원은 빌드를 파기했을 때 완벽하게 회수할 수 있다. 테스트는 현재 디자인을 올바르게 하는 것뿐만 아니라, 설계 개선 프로세스의 일부이기도 하다라는 점에 주목하자. 복잡한 하드웨어 시스템 엔지니어는 종종 모델을 구축한다(또는 적어도 컴퓨터 그래픽을 이용하여 자신의 설계를 시각적으로 표현한다). 이를 통해 설계자는 설계 자체를 검토하는 것만으로는 알아낼 수 없었던 디자인의 "느낌"을 얻을 수 있게 된다. 그러나 소프트웨어 설계에서는 이러한 모델 구축은 불가능하며, 불필요하다. 우리는 단순히 제품 자체를 빌드하면 된다. 공식 소프트웨어 검사 툴이 컴파일러와 같이 자동화되었다해도 우리는 빌드/테스트 주기를 여전히 진행한다. 따라서 공식 검사는 소프트웨어 산업에 실질적인 이득을 주지 못한다.
이것이 오늘날의 소프트웨어 개발 프로세스에서 일어나는 현상이다. 또한 복잡한 소프트웨어 설계물들은 점점 증가하는 인력과 조직에 의해 만들어지고 있다. 그리고, 이러한 설계는 몇가지 프로그래밍 언어로 코딩될 것이고 빌드/테스트 주기를 거치면서 검증되고 개선되고 있다. 이러한 프로세스는 오류를 만들기 쉬우며 특별히 엄격하지도 않다. 많은 소프트웨어 개발자는 이것이 문제를 크게 악화시키는 방법이라고 믿고 싶지 않을 것이다.
현재 대다수의 소프트웨어 개발 프로세스는 소프트웨어 설계의 다양한 단계로 세분화하려고 한다. 코드를 작성하기 전에 최상위 설계를 완료하고 동결해 두어야 한다. 그리고 테스팅과 디버깅은 구축 과정의 실수를 제거하는 데에만 필요하다. 그 사이에 있는 것이 프로그래머, 즉 소프트웨어 산업에서 건설 노동자다. 그리고 많은 사람들은 프로그래머가 "해킹"이나 "재설계"를 멈추면 소프트웨어 개발은 정말 공학 분야로 성숙한다고 믿고 있다. 프로세스가 공학이나 경제 현실을 무시하는 한, 공학 분야로의 성숙은 있을 수 없다.
예를 들어, 제조 과정에서 재작업율이 100%를 넘어 버리는 것을 용인하는 현대 산업계는 존재하지 않는다. 처음부터 제대로 구축할 수 없는 건설 노동자는 대부분의 경우 곧바로 일을 잃어 버릴것이다. 소프트웨어의 경우, 아무리 짧은 코드에도 테스팅과 디버깅 동안 수정되거나 완전히 재작성될 수 있다. 우리는 설계와 같은 창조적인 과정에서 일어나는 개선 작업은 수용하면서 제조 공정에서는 받아들이려 하지 않는다. 엔지니어가 처음부터 완벽한 설계를 만들수는 없다. 엔지니어가 그렇게 했을지라도, 그것이 완벽하다는 것을 증명하기 위해서 개선 프로세스를 지나야 한다.
일본의 경영 기법을 배웠다면, 과정에서 발생한 실수에 대해 작업자를 비난하는 것은 생산성을 저하시킨다고 배워왔다. 잘못된 프로세스 모델을 따르도록 소프트웨어 개발을 강요하는 것이 아니라, 프로세스를 수정하고 더 좋은 소프트웨어를 만드는데 도움이 되도록 해야한다. 이것이 "소프트웨어 공학"의 리트머스 테스트이다. 엔지니어링(공학)은 프로세스의 실행 방법에 대해 논의하는 것이지, 최종 설계 문서를 작성하기 위해 CAD 시스템이 필요한지 여부를 논하는 것은 아니다.
소프트웨어 개발의 큰 문제는 모든 것이 설계 과정의 일부라는 것이다. 코딩도 설계이고, 테스팅과 디버깅도 설계의 일부이며, 우리가 일반적으로 소프트웨어 설계라고 부르고 있는 것도 역시 설계의 일부이다. 따라서 소프트웨어 빌드는 저렴하지만, 설계는 놀라울 정도로 비싼 것이다. 소프트웨어는 너무 복잡하기 때문에 설계시 고려해야 할 부분과 설계 결과를 평가하는 부분에는 많이 다르다. 문제는 다양한 측면이 서로 관계되어 있다는 것이다(하드웨어 공학의 경우처럼). 상위의 설계자가 모듈의 알고리즘 설계에 관한 세부 사항을 몰라도 된다면, 아무 문제 없다. 마찬가지로, 프로그래머가 모듈의 내부 알고리즘을 설계할 때 상위 수준의 설계를 걱정하지 않아도 된다면, 이 또한 아무 문제 없다. 불행히도, 여러 디자인(설계) 계층이 서로 서로 간섭한다는 것이다. 주어진 모듈에 대한 알고리즘 선택은 상위 수준의 설계시 고려한 관점만큼이나 중요한 것이며, 소프트웨어 시스템의 전반적인 성공을 좌우하는데 중요하다. 소프트웨어 설계의 서로 다른 관점들 사이에는 중요도에 대한 서열은 존재하지 않는다. 최하위 모듈 레벨에서 설계를 실수가 최상위 수준에서 실수만큼이나 치명적인 것이 될 수 있다. 그래서 소프트웨어 설계는 모든 면에서 완벽하고 정확해야 하며 그렇게 되어 있지 않은 경우, 그 설계에 따라 소프트웨어 빌드 모두가 잘못된 것이 될 수 있다.
소프트웨어 설계 복잡도를 해결하기 위해 계층별로 설계할 수 있다. 프로그래머가 하나의 모듈 상세 설계를 할 때 수백 개의 모듈, 수천의 다른 세부 사항들을 동시에 고려할 순 없다. 예를 들어, 소프트웨어 설계자는 깔끔한 형태로 데이터 구조와 알고리즘을 설계하진 못한다는 것이 소프트웨어 설계의 중요한 관점이다. 그리고 프로그래머가 코드의 설계를 할 때 이상적인 것은 여러가지 다른 측면들을 신경 쓰지 않아야 한다.
그러나 이런 것은 실제로는 잘 되지 않는다. 그리고 그런 이유에는 합당한 핑계거리도 있다. 소프트웨어 설계는 코딩이 완료되고 테스트 될 때까지는 완벽하지 않다. 테스트는 설계 검증과 개선 프로세스의 기초가 될 것이다. 상위 레벨의 구조 설계는 완전한 소프트웨어 설계라고는 할 수 없다. 이것은 상세 설계를 위한 단순한 구조의 프레임 워크 밖에 안된다. 높은 수준의 설계를 엄격한 형태로 검증할 수 있을만큼 우리의 능력은 우수하지 않다. 상세 설계는 적어도 상세 설계 이외의 다른 요인들만큼 높은 수준의 설계에 영향을 미친다(영향을 미칠수 있게 해야 한다). 하나의 설계를 모든 관점에서 개선하는 것은 설계 주기를 통해 일어나야 한다. 설계의 일부 측면이 개선 프로세스에서 동결되는 경우라면, 최종 설계가 빈약하거나, 심지어 작동하지 않더라도 그것은 놀랄일이 아니다.
상위 수준의 소프트웨어 설계를 좀더 엄격한 공학 프로세스상에 있다라면 아무 문제 없다. 그러나, 실제 소프트웨어 시스템은 이렇게 엄격하지는 않다. 소프트웨어는 아주 복잡하며, 너무 많은 것들과 상호 연관이 되어 있다. 하드웨어에 따라 설계자의 생각대로 작동하지 않을지도 모른다. 또한 라이브러리 루틴에는 문서화할 수 없는 제약들을 가지고 있을 수 있다. 이런 종류의 문제는 모든 소프트웨어 프로젝트가 조만간 마주하게 될 것이다. 또한, 이런 문제는 초기에 발견될 방법이 없기 때문에(제대로 된 테스트를 실시했을 경우) 테스트중에 발견된다. 이러한 문제가 발견된 경우에는 설계의 변경을 강요하게 된다. 운이 좋으면 설계 변경은 지엽적인 것이 되지만, 많은 경우에 변경은 소프트웨어 설계 전체의 중요한 부분을 차지한다(머피의 법칙). 그리고 어떠한 이유로 영향을 받는 설계 부분을 변경할 수 없는 경우에는 다른 부분에서 이를 수용하게 되게 되고, 결과적으로 그 부분이 취약한 것이 된다. 관리자는 이를 '해킹'으로 인식한다. 그러나 이것은 소프트웨어 개발의 현 실정이다.
최근해 했던 프로젝트에서 내부 모듈 A와 내부 모듈 B사이에 타이밍 의존 문제가 발견되었다. 불행히도, 모듈 A의 내부는 추상화되어 은폐되어 있고 올바른 순서로 모듈 B의 호출할 수 있게 지원하는 것은 어떤것도 허용되지 않았다. 자연스레 문제가 발견된 시점에서는 A의 추상화를 변경하는 것은 너무 늦어 버렸다. 예상대로 A의 내부 설계에 맞추는 형태로 복잡한 일련의 "수정"과정이 일어났다. 초기 버전이 설치되기 전에 설계가 손상되었다는 것을 모두가 느낄수 있었다. 다음에 일어나는 새로운 수정거리들은 과거의 수정했던 것들과 상충하는 경우가 많아졌다. 이런 것들은 소프트웨어 개발 프로젝트의 일반적인 현상이다. 결국, 나는 동료와 함께 설계 변경에 대해 논쟁을 했지만, 관리의 동의를 얻기 위해 자발적으로 개발 잔업을 해야했다.
일반적인 규모의 소프트웨어 프로젝트라면 반드시 이러한 문제가 발생했을 것이다. 이러한 일을 막기 위해 다양한 시도를 했음에도 불구하고 중요한 세부 사항들은 간과하기 마련이다. 이것이 수공예와 공학의 차이다. 경험함으로써 올바른 방향으로 나아갈 수 있는 것이 수공예라는 것이다. 경험이 우리를 미지의 영역에 데려다 주게 되고 그런 다음, 시작하고, 개선된 관리 프로세스를 통해 더 나아지게 되는데 이것이 공학이라는 것이다.
소프트웨어 설계 문서는 코딩 전보다 코딩 후에 작성하는 것이 훨씬 더 정확하다는 것을 프로그래머라면 누구라도 알고 있다. 이 이유는 명백하다. 코드에 반영된 최후의 설계만이 빌드/테스트 주기를 통해 개선되는 유일한 길이다. 이 사이클을 통해 초기 설계가 변경되지 않을 가능성은 프로젝트의 모듈의 개수나 프로그래머의 수와 역 상관 관계가 있다. 즉, 이 수치는 급속히 제로에 가까워져 간다.
소프트웨어 공학은 모든 수준에서 뛰어난 설계가 필요하다. 상위 레벨에서는 특히 뛰어난 설계가 필요합니다. 초기 설계가 우수할수록 상세 설계도 뛰어나게 될 것이다. 설계자는 도움이 될만한 모든 것을 받아들여야 한다. 구조화 차트, Booch 다이어그램, 상태 전이 테이블, PDL(Program Design Language) 등 - 그것이 도움이 된다면 무엇이든 사용해아 한다. 그러나 이러한 도구와 기법이 소프트웨어 설계는 아니라는 것을 항상 염두에 두어야 한다. 결국, 우리는 진정한 소프트웨어 설계물을 만들어내야 하고, 그것은 여러 종류의 프로그래밍 언어로도 실현될 수도 있다. 따라서 우리가 만들어낸 설계물을 코드화하는 것을 주저할 필요는 없다. 우리는 필요에 따라 설계물을 기꺼이 개선할수 있어야 한다.
현재는 상위 수준의 설계와 상세 설계 모두에 적합한 설계 기법은 존재하지 않는다. 설계는 결국 어떤 프로그래밍 언어로 코딩되는 것이다. 이는 상세 설계를 시작하기 전에 상위 설계 기법에 의한 결과를 대상 프로그래밍 언어로 변환해야 한다는 것을 의미한다. 이 변환 과정에서 시간이 걸리고 오류가 만들어지기도 한다. 설계 기법이 선택한 프로그래밍 언어와 잘 맞지않아 프로그래머는 요구 수준에까지 거슬러 올라가며, 상위 레벨의 설계를 다시하고 그에 따라 코딩도 다시하는 경우가 있다. 이런 것도 소프트웨어 개발 현실에 한 부분이다.
원래 설계자가 처음부터 코드를 작성하는 것이 누군가 다른 사람에게 맡겨 버리는 것보다 결과는 더 좋다. 그래서 우리에게 필요한 것은 모든 설계 수준에 적절한 통일된 표기법이다. 다른말로 표현하면, 우리는 높은 수준의 디자인 컨셉을 알아차릴 수 있는 프로그래밍 언어를 필요로하고 있다. 여기에 C++의 여지가 있는 것이다. C++은 현실 세계에 존재하는 프로젝트에 적합한 프로그래밍 언어이며, 보다 표현력이 풍부한 소프트웨어 설계 언어이기도 하다. C++를 사용하면 설계 구성 요소에 대한 높은 수준의 정보를 직접 표현할 수 있다. 이를 통해 설계 작성을 용이하게 하고 후에 개선작업도 쉽게 할 수 있다. C++ 제공하는 강력한 형식 검사 도구에 의해, 설계 오류 탐지 프로세스도 지원된다. 따라서 디자인은 더 강력하게 되며, 본질적으로 더 나은 공학적 설계를 가능하게 한다.
소프트웨어 설계는 결국 어떤 프로그래밍 언어로 표현되어야 하며, 빌드/테스트 주기를 통해 검증되고 개선되어야 한다. 그렇지않게 되면 잘못될 것이다. 과거에 인기를 얻었던 소프트웨어 개발 도구와 기술들을 생각해 보자. 구조적 프로그래밍은 어떤 시기엔 그것이 돌파구였다. 그리고 구조적 프로그래밍은 Pascal에 의해 인기를 얻었고 이 Pascal 자신도 구조적 프로그래밍의 인기를 등에 업었기도 했다. 객체 지향 설계는 새로운 조류이며, C++이 그 중심에 있다. 그럼 인기가 없었던 것들을 생각해 보자. CASE 도구? 확실히 인기는 얻었지만, 보편적이지는 못했다. 구조화 차트? 이것도 같았다. 마찬가지로 Warner-Orr 다이어그램, Booch 다이어그램, 객체 다이어그램 등이 나을지도 모른다. 각각 장점이 있지만, 각각은 진짜 소프트웨어 설계가 아니라는 공통된 단점을 가지고 있다. 사실 광범위하게 보급되었다고 할 수 있는 소프트웨어 설계 기법은 PDL이고, 그것이 우리의 눈에 어떻게 비쳐지고 있는지 생각해 볼 필요가 있다.
이것은 프로그래밍 기술, 그리고 특히 현실 세계에서 프로그래밍 언어의 개선이 소프트웨어 업계에서 가장 중요하다는 점을 소프트웨어 업계 전체가 직관적으로 알고 있다는 것을 나타낸다. 또한 프로그래머가 설계에 관심을 가지고 있다는 것을 의미하고 있다. 더 표현력이 풍부한 프로그래밍 언어가 이용 가능하게되면 소프트웨어 개발자는 그것을 사용할 것이다.
또한 소프트웨어 개발 프로세스가 어떻게 변해왔는지 생각해보자. 한때는 워터폴 프로세스를 사용했었다. 그리고 지금은 나선형 개발이나 래피드 프로토타입에 대해 이야기하고 있다. 이러한 기법은 종종 "위험 감소"나 "제품 출시 가속화"등의 관점에서 정당화되었지만, 실제 결과는 라이프 사이클 동안의 코딩 작업을 좀 더 일찍 시작할 수 있었을 뿐이다. 그러나 이것은 옳은 방식이다. 빌드/테스트 주기를 통해 설계를 조기에 검증하고 개선할 수 있도록 하는 것이다. 또한 이것은 상위 수준의 설계를 담당하는 소프트웨어 설계자가 상세 설계 시점까지 있도록 해준다.
위에 기술한것 처럼, 공학은 최종 제품이 어떤 모습이 될 것인가가 아니라 당신이 어떻게 프로세스를 실천하는가에 해당하는 것이다. 소프트웨어 업계에 있는 우리는 엔지니어와 가까이에 있지만, 일부분은 인식을 바꾸어야 한다. 프로그래밍 및 빌드/테스트 주기가 소프트웨어 개발 공학 프로세스의 핵심이다. 우리는 이러한 작업을 제대로 실천해 나갈 수 있도록 관리해야 한다. 빌드/테스트 주기의 경제성이나 소프트웨어 시스템이 실질적으로 어떤한 것도 표현할 수 있다는 사실을 생각하면 소프트웨어 설계를 검증할 수 있는 범용적인 방법을 찾는 것은 쉽지 않다. 우리는 프로세스를 개선할 수만 있을뿐, 이 상황을 벗어날 수는 없다.
마지막 요점: 공학 설계 프로젝트의 목표는 어떤 문서를 작성하는 것이다. 분명, 실제 설계 문서가 엄청 중요하지만, 제조해야 한다는 것은 그것만으로는 안된다. 결국, 누군가가 그 소프트웨어를 사용하게 될 것이고 결국 대부분의 경우 해당 시스템은 나중에 보강되고 수정될 것이다. 이것은 하드웨어 프로젝트와 마찬가지로 소프트웨어 프로젝트들에서도 보조 문서는 중요하다는 의미이다. 설계 프로세스와 직접 관련이 없는 사용자 설명서, 설치 설명서나 기타 문서들은 당분간 무시하더라도 보조 설계 문서에 대해 해결해야 할 두가지 중요한 요구가 여전히 존재하고 있다.
보조 문서의 용법중에 하나는 설계에 직접 통합될 수 없는 문제 영역에서 중요한 정보를 포착하는 것이다. 소프트웨어 설계는 문제 영역에서 소프트웨어의 개념에서 모델의 개념을 만드는 작업이 포함되어 있다. 이 과정에서 문제 영역에 대한 개념의 이해를 확립해야 한다. 보통의 경우, 소프트웨어 영역중에 직접 모델링할 필요가 없는 정보까지 이해하고 있어야 하지만, 그럼에도 불구하고 설계자는 본질적인 개념이 무엇인지, 그리고 어떻게 모델링하는 것이 최적인지를 확정할 수 있도록 도움을 준다. 즉, 나중에 모델을 변경해야 하는 경우에 대비하여 이러한 정보를 어딘가에 포착해 두어야 한다.
보조 문서의 또 하나의 중요한 용도는 설계 자체에서 직접 추출하기 어려운 설계상의 여러 측면을 문서화해 둔다는 것이다. 이것은 상위 레벨 및 하위 레벨 두 방면 모두 포함된다. 이런 관점들의 많은 부분을 도표로 표현하는 것이 최고다. 따라서 이런 것들은 소스 코드의 주석에 표현하기 어려운 것들이다. 그러나 여기에서는 프로그래밍 언어 대신 그래픽 소프트웨어 설계 기법을 사용한다는 등의 논쟁은 하지 않는다. 이제 하드웨어 분야의 설계도에 글로 설명이 필요하다는 주장과 크게 다르지 않다. 그러나, 진정한 설계를 결정 짓는 것은 보조 문서가 아니라 소스 코드라는 것을 잊지 마라. 이상적으로는 소프트웨어 툴에 의해 설계에서 소스코드가, 보조 문서가 생성되게 될지도 모른다. 그러나 이것은 지나친 예측일수도 있다. 차선책으로는 프로그래머(또는 테크 라이터)가 소스 코드에서 특정 명세 정보를 추출하고 여러 다른 방법들로 문서화를 지원하는 도구가 있을수도 있다. 그러나 이러한 문서를 수동으로 최신 상태로 계속 유지하는 것은 매우 어렵다. 이것은 또한 표현력이 풍부한 프로그래밍 언어가 필요하다는 또 다른 논쟁이 될 수 있다. 또한 이러한 보조 문서를 최소한으로 억제하고 프로젝트 후반까지 가능한 한 그것을 비공식으로 유지하자는 논의도 있다. 다시 말하지만, 우리는 더 나은 도구를 사용할지도 모른다. 그렇지 않으면 우리는 언제까지나 연필, 종이, 화이트 보드를 계속 사용하게 될 것이다.
전체를 요약하면
- 진정한 소프트웨어는 컴퓨터 내에서 실행되는 것이다. 이것은 어떤 자기 매체에 저장된 1과 0의 시퀀스이다. 즉, C++ (또는 다른 프로그래밍 언어)로 기술된 프로그램 목록에는 없다.
- 프로그램 목록은 소프트웨어 설계를 표현한 문서이며, 소프트웨어 설계물은 컴파일러와 링커에 의해 실제로 제조(빌드) 된다.
- 진정한 소프트웨어를 구축(빌드)하는 것은 놀라울 정도로 저렴하며, 컴퓨터의 고속화와 함께 더 저렴해지고 있다.
- 진정한 소프트웨어를 설계하려면 놀라울 정도로 비용이 소요된다. 이것은 소프트웨어가 놀라울 정도로 복잡하고 사실상 소프트웨어 프로젝트의 모든 단계가 설계 프로세스의 일부가 되어 있기 때문이다.
- 프로그래밍은 설계 활동이다. 우수한 소프트웨어 설계 프로세스는 이 점을 인식하고 코딩을 할 때는 주저하지 않는다.
- 코딩은 우리가 믿고 있는것보다 더 의미있는 작업이다. 코드에 의해 설계물이 그려내는 과정은 종종 간과이나 추가 설계를 할 필요성에 대해 가르쳐준다. 이러한 일을 빨리 진행하면, 디자인은 더 나은 것이 될 것이다.
- 소프트웨어 빌드는 거의 비용이 들지 않기 때문에 공식 공학적 검증 기법이 실제 소프트웨어 개발에 많이 사용되는 것은 아니다. 증명하려고 하는 것보다 단순히 설계를 빌드하고 테스트하는 것이 쉽고 저렴하다.
- 테스팅과 디버깅은 설계 활동이다. 이것들은 다른 공학 분야의 설계 검증이나 개선 프로세스와 동일한 것들이다. 우수한 소프트웨어 설계 프로세스는 이 점을 인식하고 있기 때문에 이 단계들을 부실하게 하지는 않는다.
- 그 밖에도 설계 활동이 존재하고 있다. 이들은 최상위 설계, 모듈 설계, 구조 설계, 아키텍처 설계 등의 이름으로 불리고 있다. 우수한 소프트웨어 설계 프로세스는 이 점을 인식하고 있기 때문에 의식적으로 이 단계들을 포함하고 있다.
- 모든 설계 활동은 상호 작용을 한다. 우수한 소프트웨어 설계 프로세스는 이 점을 인식하고 있기 때문에 다양한 설계 단계에 변경의 필요한 경우 때때로 대담한 설계 변경을 허용하고 있다.
- 많은 다양한 소프트웨어 설계 기법은 유익한 것들을 내포하고 있다. 설계 프로세스를 원할하게 도움을 주는 보조 문서나 도구도 있다. 그러나 이러한 것들이 소프트웨어 설계에는 없다.
- 소프트웨어 개발은 아직도 공학 분야라기보다는 수공예쪽에 가깝다. 이것은 주로 설계 검증 및 개선하는 중요한 프로세스에서 엄격성이 결여되어 있기 때문이다.
- 궁극적으로 소프트웨어 개발 진정한 발전는 프로그래밍의 발전 즉, 프로그래밍 기술의 발전에 달려있다. C++이 이러한 발전속에 있다. 더 좋은 소프트웨어 설계를 직접 지원하는 주류 프로그래밍 언어이기 때문에 인기가 폭발적인 것이다.
- C++ 올바른 방향으로의 한걸음 나아가고 있지만, 더욱 발전이 필요하다.