2003년부터, Worcester Polytechnic Institute에서 학부생들을 대상으로 6주 코스의 소프트웨어 엔지니어링을 강의하고 있다. 내 제자들은 내가 조만간 아래 항목을 시험문제로 낼 것을 눈치챘을 것이다.
소프트웨어 엔지니어링과 다른 엔지니어링의 차이점을 논하라.
소프트웨어 엔지니어링에는 기본적인 특징이 있으며 바로 이것을 교육하고 학습하는 것이 매우 까다롭다는 것을 학생들이 이해해 주기 바란다.
위 같은 질문에는 한 가지 답만 존재하는 것은 아니다. 사실 좋은 답안일수록 여러 가지 차이점들이 규명될 것이다.
- 소프트웨어는 부드럽다(soft) 적응력이 있으며 변경되기도 한다. 기계 엔지니어들이 설계하고 구현한 물리적 장치와는 매우 다르다.
- 광범위하게 적용될 수 있는 몇 가지 소프트웨어 규칙들이 있다. 화학 엔지니어와 전기 엔지니어들은 물리학과 화학의 기본 원칙을 따라 설계한다. 만약 소프트웨어 법칙이 있다면 아직 그것들을 발견하지 못한 것 같다. 컴퓨터 하드웨어 디자이너들은 정확한 공식을 사용하면 그들이 설계하는 칩에서 발생하는 열의 양을 계산할 수 있지만 소프트웨어 엔지니어들은 프로그램 사이즈 같은 제품 속성을 측정할 방법 조차도 합의에 이르지 못한다.
- 소프트웨어는 대량으로 생산되지 않는다. 자동차 같은 경우는 대량 생산이 가능하다. 액세서리는 변화시킬 수 있지만 기본 디자인을 반복적으로 사용한다. 소프트웨어는 그렇지 않다. OS 같은 특정 프로그램을 복사하여 수백만 사용자들에게 배포할 수는 있지만 단 하나의 실제 프로그램만 구현해야 한다. 제조 과정에는 카피를 만드는 것이 포함되지만 또 다른 동일 제품을 구현하는 것은 포함되지 않는다.
- 소프트웨어의 스팩은 지속적으로 변한다. 심지어 개발 사이클 후반에도 바뀔 수 있다. 절반 정도가 완성된 다리를 보고, "저기요, 내가 보기에 이 다리가 여기 보다는 저쪽에다 짓는 것이 나을 것 같은데요! " 라고 말하는 고객은 없을 것이다. 불행히도 그와 같은 요구 사항에 대한 변경 요청은 소프트웨어에는 끊임없이 발생한다.
일단 내 학생들이 소프트웨어 엔지니어링이 다른 유형의 엔지니어링과 다르다는 것을 이해했다면, 엔지니어링이라는 말이 실제로 소프트웨어 중심의 시스템을 구현하는데도 적용되는지 궁금할 것이다. 나는 끊임없이 이 질문과 싸웠다. 지난 12월 칼럼에서,1 언급했듯이 우리의 교육 내용은 지난 반세기 동안 성숙했고 진보해 왔다. 하지만 잘못된 것도 있다. 우리가 만든 소프트웨어 대부분이 엔지니어링 되는 것이 아니라 여전히 생산(produced)되고 있다. 그리고 여전히 너무나 많은 프로젝트가 실패하고, 저질의 소프트웨어가 생산된다.
해결책은 무엇인가? 쉬운 해답은 없다. 대부분의 소프트웨어 프로젝트에 강력한 엔지니어링 원리를 적용한다고 해서 결과가 나아진다고 생각하지 않는다. 오히려 제품 제공만 늦추게 될 것이다. 대신, 우리는 소프트웨어 엔지니어링의 개념과 이 분야에 진입하는 사람들을 교육하는 방식을 다시 생각해야 한다.
소프트웨어 엔지니어링에 대한 많은 정의가 있다. 가장 첫 번째가 North Atlantic Treaty Organiation (NATO)가 후원한 1969년 컨퍼런스에서 거론되었다.
소프트웨어 엔지니어링은 신뢰성 있고 실제 머신에서도 효율적으로 작동하는 소프트웨어를 얻기 위해 올바른 엔지니어링 원칙을 확립하고 사용하는 것이다. 2
오늘날 널리 채택되고 있는 정의는 Institute of Electrical and Electronics Engineers (IEEE)(1993년)의 것이다.
소프트웨어 엔지니어링: (1) 소프트웨어 개발, 작동, 관리에 체계적이고 정량화 될 수 있는 방식을 적용하는 것. 다시 말해서 소프트웨어에 엔지니어링을 적용하는 것. (2) (1)3의 방식을 연구하는 행위.
첫 번째 정의를 생각해 보자. 많은 개발 프로젝트들은 신뢰성 있는 소프트웨어를 만든다. 또한 소프트웨어를 경제적으로 생산한다. 만약 그렇게 하지 않았더라면 그렇게 많은 이윤을 남기는 소프트웨어 기업은 있을 수 없다. 하지만 이러한 기업들은 올바른 엔지니어링 원리를 소프트웨어 구현에 적용할까?
올바른 엔지니어링 원리에 대한 일반적인 동의가 있는지는 모르겠다. 두 번째 정의는 좀더 확실하다. 그렇다면 이것이 소프트웨어 시스템이 실제로 구현되는 방식을 더 반영한다고 볼 수 있는가?
대부분의 엔지니어들은 강력한 문제 분석을 적용하고 제안된 솔루션의 모델을 구현한다. 전기 엔지니어들은 회로판과 함께 모델을 구현한다. 물리학 법칙을 사용하여 다양한 속성에 기대 값을 결정하고 실제 값을 측정할 때 정밀 기구를 사용한다. 화학 엔지니어들은 파일럿 작동을 구현하여 화학 제조 과정을 프로토타이핑한다. 항공 엔지니어들은 그들의 모델을 풍동 실험(wind tunnels)을 통해서 퍼포먼스를 측정한다. 도시 엔지니어들은 값비싼 구현 단계로 돌입하기 전에, 다리와 다른 구조물들의 수학적 모델을 구현하여 이것이 감당할 무게와 스트레스가 얼마나 큰지를 측정한다.
또한 대부분의 엔지니어링 교육에서 엔지니어들은 일반적인 컴포넌트를 사용한다. 이는 사용자 컴포넌트를 설계 및 구현하는 것 보다 저렴하다. 이들은 필요한 컴포넌트의 스팩을 결정하고, 카탈로그를 보며 주문을 한다. 그들은 비교적 정확하게 구현과 제조 비용을 산정할 수 있다. 하지만 이것이 소프트웨어를 비롯한 모든 엔지니어링 교육에 적용되는 것은 아니다. 비용 초과도 허다하다.
왜 소프트웨어 엔지니어들은 이렇게 견고한 엔지니어링 방식을 사용하지 않는가? 내가 보기에 이 분야에서 일하는 사람들을 교육하는 방식에도 잘못이 있는 것 같다.
나는 최근에 다섯 개의 전형적인 대학생용 소프트웨어 엔지니어링(SE) 교과서4에서 어떤 주제를 다루는지를 보았다. 실망스러웠다. 이 모든 책에서는 프로세스, 요구 사항, 디자인, 테스팅, 프로젝트 같은 것을 다루고 있다. 대부분 분석 섹션도 있다. 요구 사항 관리와 디자인과 분석이 적어도 하나의 번들을 형성하고 있다. 하지만 대부분이 특정 프로세스나 기술의 표면을 단순히 건드린 것에 지나지 않았다.
예를 들어, 이들 모두가 사용 케이스를 요구 사항과 분석 툴로서 언급하고 있다. 다섯 개의 책 총 3,500 페이지 중에서 단 43 페이지만이 사용 케이스를 실제로 논하고 있다. 이는 평균 하나의 텍스트북 당 6 페이지 정도이다. 그 6페이지마저도 좋은 사용 케이스를 작성하는 것과 관련이 되었다면 좋으련만 그렇지도 않다. 대신 사용 케이스 다이어그램과 컴포넌트를 설명하고 있다. 단 하나의 책(Maciaszek) 만이 23 페이지에 걸쳐 사용 케이스를 다루고 있고 케이스 스터디에 이들을 적용하고 있다.
이 책들 어느 것도 진정한 요구 사항들에 대해 충분한 공간을 할애하지 않는다. 어떤 책은 확인과 입증에 짧은 섹션을 갖고 있지만 이들은 간단히 IEEE 표준이나 다른 공용 방식을 가리키고 있다. 이는 완전히 공간의 낭비이다. 소프트웨어 엔지니어들이 프로그램이 정확한지를 입증하기 위해 실제로 어느 정도의 시간을 투자하는가? 거의 없다. 그와 같은 일반적인 방식은 실제로는 적용하지 않는 것들이다.
대부분의 소프트웨어 엔지니어링 텍스트는 프로젝트 플래닝과 평가에도 일정량의 페이지를 할당한다. Constructive Cost Model (COCOMO)5같은 툴도 포함해서 말이다. 여러분의 경우는 어떤지 모르겠지만 이 분야에서30년 넘게 일해온 나 조차도 COCOMO를 사용한 적은 없었다. 이것이 나쁜 툴이라는 의미가 아니라 소프트웨어 엔지니어로서 해야 할 가장 중요한 일은 아니라는 의미이다.
일반적으로 텍스트북은 큰 프로젝트에만 적용되는 방법들을 강조하기 마련이다. 7명에서 10명의 개발자가 투입되는 프로젝트 방식에는 공간 할애가 적다. 하지만 이러한 방식들도 첫 번째 프로젝트를 성공하고픈 신참 엔지니어들에게는 중요한 자료이다. 텍스트북은 또한 특정 주제들의 중요성을 왜곡한다. 어떤 필자는 "문서화는 소프트웨어 엔지니어링의 핵심" 이라고 주장한다. 만약 내가 지원자와 면접을 할 때 지원자가 "내가 지금 소프트웨어 엔지니어링에 지원하려고 하는데, 저는 문서화 능력이 우수합니다." 라고 한다면 내가 그를 과연 고용하게 될지 의심스럽다. 하지만 지원자가 "나는 반복적인 개발에 대해 이해하고 있고 요구 사항에 맞는 소프트웨어를 제공하는 것에 초점을 맞춰 일하고 있습니다." 라고 한다면 나는 그 사람을 당장 고용할 것이다.
텍스트북의 "개론" 스타일의 접근방식도 가장 큰 문제라고 본다. 우리가 일반적인 소프트웨어 엔지니어링만 가르친다면 학생들은 실제 소프트웨어를 구현하는 방법을 전혀 배우지 못한다. CCOCOMO 같은 플래닝 툴을 사용하는 수 백만 줄의 코드 시스템에서 작업하거나 Capability Maturity Model(CMM) Level 5 기업에서 일했더라도 구체적이지 않은 접근 방식은 결국은 쓸모가 없다. 학생들은 그들이 실제로 사용할 수 있는 것을 배울 때 가장 좋은 것을 배운다.
그렇다면 최상의 대안은 무엇인가?
나는 2년 동안 기초적인 소프트웨어 엔지니어링 코스를 강의한 후에 어떤 것이 실제로 유용한지를 깨달았다. 학생들에게 이론과 불확실한 다양한 기술을 가르치는 대신 소프트웨어 개발을 가르쳤다. 이것은 소프트웨어 엔지니어링의 적용 측면이다. 한 주 동안 나는 학생들이 조건 프로젝트를 시작하도록 했다. 그리고 나서 고객은 무엇이 구현되기를 바라는지, 그것을 어떻게 구현하는지, 어떤 프로세스를 사용하는지, 팀을 어떻게 조직하는지 등을 규명하도록 했다. 마지막 7주차에 그들이 실제로 이루고 배운 것이 얼마나 많은지를 돌아보며 놀랐다.
나는 학생들이 프로젝트에 맞는 프로세스 엘리먼트를 선택하는 방법을 알려준다. 그들에게 두 가지의 기술과 툴을 사용하는 방법을 알려준다. 이러한 몇 가지 엘리먼트와 툴을 사용하여 효용성을 누릴 수 있도록 하고 학생들의 능력을 확대시킬 수 있는 배경과 자신감을 심어주려고 한다. 7주동안 내 소프트웨어 엔지니어링을 배우는 학생들은 다음 내용을 적극적으로 수행한다.
- 요구 사항들을 분석하고 관리한다. 일반적으로 사용자 스토리와 사용 케이스에서 요구 사항들을 포착한다. 학생들은 단기 프로젝트에는 사용자 스토리가 유용하다는 것을 알고 있지만 사용 케이스가 모든 것을 하나로 연결하여 시스템 테스팅을 더욱 효과적으로 수행한다는 것도 알고 있다. 게다가 그들은 요구 사항이 변한다는 것도 배우고 그 변화에 대응해야 한다는 것도 알고 있다.
- 소프트웨어를 반복적이고 점증적으로 개발한다. 팀은 첫 강의 후 11일이 지난 후에 클라이언트에게 소프트웨어 데모를 실행해야 한다. 그 후 매 주말에 팀은 추가되고 완성된 기능들을 데모해야 한다. 고객의 우선순위가 기준이다.
- JUnit 같은 툴을 사용하여 소프트웨어를 단위 테스트 한다. 단위 테스트는 모든 프로그래밍 할당의 일부이고 프로젝트의 한 부분이다.
- 작업 계획을 세운다. 작은 프로젝트의 경우 extreme programming(XP) 방식이 유용하다.6 매 주, 팀은 고객에게 이전 반복에서 완료된 작업을 기준으로 특정 작업 단위를 선택하도록 한다.
- 작업을 문서화 한다. 학생들은 미래의 학생들이 그 프로젝트를 이해할 수 있도록 문서를 만들어서 제출해야 한다. Unified Modeling Language(UML)를 활용하여 클래스와 시퀀스 다이어그램을 만든다. 사용자 문서도 제출해야 한다.
- 리스크를 규명하고 완화한다. 각 팀은 리스크 리스트를 개발하고 리스트의 각 항목 별로 완화 전략도 세운다. 팀은 각 리스트를 지속적으로 업데이트 해야 하는데도 좀처럼 그렇게 하려 들지 않는다. 시간이 별로 없기 때문이다.
- 팀의 일원으로서 본분을 다한다. 현재 클래스에는 43명의 학생들이 있다. 그들은 한 날에 첫 번째 숙제를 받고 이틀 동안 팀을 구성한다. 학교의 SourceForge 시스템에 프로젝트를 설치한다. 각 팀에는 멘토가 배치된다. 멘토는 나 또는 조교가 맞는다. 나는 팀들이 그들 자신의 작업 스타일을 개발하고, 효과적으로 교류하며 팀의 향상을 위해 갈등을 해결하기를 바란다. 7 심한 경우 팀은 나에게 팀 일원을 탈퇴 시킬 것을 요청할 수 있다. 정당한 사유가 있으면 해당 팀원은 팀에서 탈락된다. 그는 다른 팀에 할당되거나 그렇지 못할 경우 코스를 탈퇴하게 된다.
7주 동안의 프로젝트에서 학생들은 많은 것을 배운다. 그들은 형성-폭풍-수행(form-storm-perform) 프로세스를 거치게 된다. 가끔 그들은 이전의 경험이나 우정에 기반하여 팀원들을 선택한다. 결국 친구의 작업 스타일이 자신과 꼭 맞지 않는다는 것을 발견하게 된다. 이것은 "폭풍" 기간에 돌입할 때이다. 그들은 다른 팀원들에게 화가 나있지만 무엇을 해야 할지를 모른다. 한 두 명의 학생들이 내 사무실로 찾아와 문제 팀원들을 어떻게 다룰지를 얘기하면 그들이 해결책을 모색할 수 있도록 돕고 있다. 드문 경우지만 내가 학생을 해고해야 할 때도 있다.
한 팀이 그 주 동안 많은 일을 수행했지만 데모를 실행할 준비가 안될 때도 있었다. 나는 고객의 입장이 되어 그들을 질타했다. 그런 다음 나는 팀에게 프로그래밍 파티를 열 것을 제안했다. 그들은 협동하여 실제로 무엇인가를 만들어 냈다. 그리고 실행되었다. 또 어떤 경우에는, 팀이 좋은 기능을 구현했지만 이는 고객이 요청하지 않은 경우도 있었다.
나의 학생들이 소프트웨어 엔지니어링에 대해 과연 배웠을까? 나는 그렇다고 생각하지 않는다. 내 학생들이 졸업한 후에 소프트웨어 개발 팀의 멤버로서 일할 수 있을까? 이것은 확신한다. 내 수업을 들은 학생들은 소프트웨어 개발 팀의 능력 있는 팀원이 될 수 있다. 그들은 프로세스에 대해 알고 있고 실행 방법을 알고 있다. 그들은 요구 사항에 맞는 소프트웨어를 만들 수 있으며 소프트웨어를 테스트할 수 있다. 그들은 무엇보다도 실제 세계의 지속적인 변화를 다루는 방법을 알고 있다.
나는 최근에 어떤 기업의 CEO에게 다음과 같은 말을 들었다. "실제 세계는 매우 복잡하다. 제품이 시장에 나오기 위해서는 작업을 조직하고 협업하고 보존할 수 있어야 한다. " 나의 학생들은 그런 혼란을 다룰 준비가 되어있다. 전에 내가 가르쳤던 학생이 이메일을 보내서 내가 가르쳤던 것을 실제 작업에 적용한다는 내용을 보면 기쁨을 느낀다.