일단 부딪혀 본다? 임베디드는 그렇게 개발하는 것이 아닙니다.

 

“일단 부딪혀 보라”는 마크 주커버그가 페이스북의 직원들에게 강조하고 있는 개발 문화입니다. (비록 완벽하지는 않지만) 새로운 기능을 빠르게 개발하는 데에 있어서는 매우 훌륭한 방침 같지만, 이러한 접근법을 임베디드에 개발에 적용하면 곧 생각이 바뀌게 될 것입니다.

 이유는   분야가 완전히 다르기 때문입니다페이스북은   데이터베이스 중심의 개발이 이루어지는 환경으로새롭게 개발된 기발한 기능이 설사 제대로 작동하지 않는다고 하더라도 그다지  문제는 없습니다임베디드 시스템은 태생적으로 자원의 제약을 받으며대부분의 경우 하나의 기능또는   되는 소수의 기능을 상정해 개발됩니다그러므로 “일단 부딪혀 본다 식의 사고방식으로 베디드 개발에 임하게 되면 전체 시스템이 무용지물이 되고 마는 경우도 생길 수가 있습니다해당 임베디드 시스템에서 제공하고자 하는 기능이 무엇인가에 따라운이 좋으면 체면을 구기는 수준으로 끝날  있지만최악의 경우는 대재난이 발생하게  것입니다. 

이것이 의미하는 바가, 고속 프로그램 개발 기법(RAD, Rapid Application Development) 방법을 사용할 수 없다는 것은 아닙니다. 매우 신중해야 한다는 것입니다.

서두른다고 개발이 빨라지는 것도 아니고생산성은 더더욱 올라가지 않는다.” 

코드 품질은 뒷전으로 하고, 속전속결로 개발을 진행하게 되면 코드는 빨리 나올 수가 있습니다. 이러한 방식을 WISCY(‘위스키’라고 읽습니다.)라고 하는데, Why Isn’t Somebody Coding Yet? 즉 왜 아직도 코딩을 하지 않고 머뭇거리고 있느냐는 의미입니다. 이것은 또한 이렇게 개발된 코드에 대해서 시험을 전혀 진행하지 않거나, 하더라도 매우 건성으로 하는 것을 의미하기도 합니다. 이 두 가지 모두 프로젝트에 문제가 발생하는 원인이 될 수가 있으므로, 소프트웨어 품질 관리(Software Quality Assurance)의 모범 규준을 준수하는 것이 필요합니다.  

개발자를 닦달해 새로운 기능을 추가하게 하는 경우(심지어 버그를 고치도록 닦달하는 경우), 시스템의 나머지 부분에 대한 통합 테스트는 건너뛰는 경우가 많습니다. 그저 데스크 체킹 방식으로 방금 작성한 코드에 대해서만 몇 건의 테스트를 해 보는 것이 전부일 것입니다. 이것은 일단 코드부터 납품하고 보자는 속전속결의 문화가 원인입니다. Lemi Ergin이 말한 바 있듯, “개발을 서두른다고 하여 속도가 빨라지는 것도 아니요, 생산성이 높아지는 것도 아닙니다. 단지 스트레스만 늘어나고, 집중을 어렵게 할 뿐입니다. 우리가 필요로 하는 것은 창의성과 효과성, 그리고 집중입니다.”[1] 소프트웨어의 빠른 전개를 위한 출발점은 코드 품질인 것입니다. 

임베디드 개발에 필요한 것은 바로 확장성 

개발자가 코드를 작성할 때에는 확장성을 촉진하고, 시스템의 복잡성을 줄여 주는 개발 프로세스에 집중해야 합니다. 또한 개발자는 항상 “기술적 부채”(technical debt)를 줄여 나갈 수 있는 방법을 모색해야 합니다. 시스템을 간결하게 유지함으로써, 개발자가 기능을 추가하거나, 시스템을 필요 시 확장하기가 용이해 집니다. 하지만 이를 위해서는 시간을 들여 시스템을 적절히 설계해야 합니다. 

RAD 상황에서는 “빠르고 더러운” 해결책이라도 빨리 찾고 싶은 유혹을 받게 됩니다. 이러한 접근법은 개발팀이 현재 직면하고 있는 문제는 해결해주지만, ‘기술적 부채’라는 말이 생겨난 이유가 되기도 합니다. 확장성 있는 솔루션을 기획해 두지 않는다면, 결국 개발자는 이후 프로젝트에서 어플리케이션을 다시 작성하는 운명에 처하게 되며, 버그 해결이나 새로운 기능을 추가하는 것도 소프트웨어가 서로 철저히 예속되어 있어, 악몽과 같은 경험이 될 것입니다. 예속이란 소프트웨어 모듈이 서로에게 의존해야 하는 상황으로, 코드(또는 임베디드 시스템의 경우는 코드의 타이밍도 포함됩니다) 한 줄로 인해 시스템 전체가 먹통이 되어 버리기도 합니다. 그렇지만 이와 같은 수준의 기획을 세우는 것은 마감이 닥친 개발자에게는 사치에 불과하며, Kelsie Anderson이 말했던, “카우보이 코딩”으로 이어질 수 있습니다. 이것은 속도를 위해 소프트웨어의 품질을 희생하는 것으로 시간이 흐름에 따라 시스템은 좀 더 복잡해지고, 모듈 간의 예속이 심해지며, 기술적 부채도 늘어납니다. 그러므로 이것은 실질적으로는 개발의 속도가 늦어지는 원인이 되며, 개발의 비용도 더 늘어납니다[2]. Ergin이 말했듯, “양질의 코드 베이스가 없이는, 어질리티도 없는 것입니다”[1]. 

간단한 진리 – 모든 것의 시작은 코드 품질입니다. 

일정에 밀려 코드를 짜깁기 할 시간조차 없는데 어떻게 코드 품질을 개선할 수 있을까요? 다행스럽게도 MISRA, CWE, CERT C와 같은 코드 표준으로부터 도움을 얻을 수가 있습니다. 앞서 코드 표준에 대해 소개하는 순서도 있었지만, 이러한 표준의 핵심은 위험한 코딩 방식을 지양하고, C  C++ 언어 자체에 존재하는 허점을 피할 수 있도록 함으로써 안전하고, 신뢰할 수 있는 코딩 방식을 장려하는 데에 있습니다. 

코드 분석 도구를 사용하면 자동으로 코드를 스캔해 이러한 표준에서 벗어나는 부분을 찾아 줍니다. 따라서 데스크 체킹을 하는 가운데에서도 이러한 문제를 찾아 빠르게 고칠 수가 있습니다. 바꾸어 말하면, 코딩 작업의 “흐름”을 방해하지 않으면서 즉각적으로 코드에 대한 피드백을 받아 볼 수가 있는 것입니다. 이와 같은 즉각적인 피드백을 통해, 빌드 서버로부터 나중에 피드백을 받아보는 것에 비해 50%나 더 빠른 속도로 버그를 고칠 수가 있습니다.[3] 코드 표준을 따르게 되면 코드의 품질을 즉각적으로, 그리고 비약적으로 향상시킬 수가 있으며, 솔루션 상에 존재하는 기술적 부채를 줄여 줄 수 있습니다. 동시에, 코드 작성 시 발생하는 버그 자체의 수도 줄어들게 되며, 발생하는 버그도 좀 더 빨리 찾아 수정하는 것이 가능합니다. 이와 같은 체계적인 코딩 접근법을 사용하면 새로운 기능을 추가하는 것도 더 쉽습니다. 즉, 새로운 기능을 더 빨리 추가할 수가 있는 것입니다. 하지만 양질의 코드 베이스를 확보했다고 하더라도 넘어야 할 산이 하나 더 있습니다. 바로 코드를 적절히 테스트하는 것입니다.  

코드 품질과 테스트는 반드시 함께 가야 합니다. 

Steve McConnell은 자신의 세미나 발표인 Code Complete에서 테스트와 코드 품질 간의 관계를 다음과 같이 다시 한 번 강조하고 있습니다. 

“테스트 자체만으로는 소프트웨어의 품질이 올라가지 않습니다. 테스트 결과는 품질을 나타내는 지표일 뿐, 그 자체로는 품질을 개선해 주지 않기 때문입니다. 소프트웨어의 품질을 개선하기 위해 테스트의 횟수만을 늘리는 것은 저울에 자주 올라가면 살이 빠질 것으로 기대하는 것과 같습니다. 저울에 올라가기 전 무엇을 먹었느냐가 체중을 결정합니다. 따라서 어떠한 소프트웨어 개발 기법을 사용하는가에 따라 테스트 중에 얼마나 많은 에러가 발생하는지를 좌우할 것입니다. 살을 빼고 싶다면, 저울을 새로 살 것이 아니라 식습관을 바꿔야 합니다. 소프트웨어를 개선하고 싶다면, 테스트 횟수만을 늘리지 말고, 개발을 좀 더 잘 하십시오.”[4] 

과거에는 수작업으로 테스트를 진행하는 비중이 매우 높았습니다. 하지만 새로운 툴이 등장하면서, 개발팀이 테스팅을 자동화 할 수 있는 길이 열리게 되었습니다. 이러한 툴의 효율은 업체별로 차이가 있지만, 여러 가지 놀라운 기능을 지니고 있는 툴들도 있습니다. 예를 들어 요구 사항 추적(코드가 사양서 상의 요구 조건을 충족하는지, 아니면 그저 ‘겉치레’에 불과한 코드인지), 유닛 테스트(해당 모듈이 그 기능을 모두 제대로 발휘하는지), 통합 테스트(각 유닛이 서로 유기적으로 잘 작동하는지) 등이 이러한 기능에 해당됩니다. 하지만 테스트 자동화는 개발자에게 있어 양날의 검이 될 수도 있습니다. 미 국방부는 개발 시 자동화 테스팅이 실제로 구현할 수 있는 기능, 그리고 자동화 테스트를 통과한다고 할 시, 이것이 코드의 출시 준비 상태에 대해 어느 정도의 의미를 지니는 지와 관련해 현실에 입각한 인식을 지니도록 권고하고 있습니다.[5] 

임베디드 소프트웨어 분야에서 가장 흔히 발생하는 문제점 두 가지가 바로 레이스 상황(어느 조건이 먼저 완결되는 가에 따라 결과물에 차이가 발생하는 상황), 그리고 초기화 문제입니다. 이 두 문제는 모두 매우 희귀한 상황에서만 발현되나, 재현이 어려워 이를 발견 및 수정하기 어려운 문제점을 야기할 수가 있습니다. 자동화 테스팅은 일반적으로 이러한 종류의 문제점을 발견해 내는 데에는 취약하며, 이것이 발현되도록 하기 위해서는 창의적인 방법을 사용해야 하는 경우도 있습니다. 고전적으로 전해 내려오는 방법 중의 하나가 바로 기기의 여러 버튼을 동시에 누르는 것입니다. 버튼을 동시에 눌렀을 때 (동일한 장치 사이클 상에서) 발생하는 결과가 혹시 다릅니까? ISR(Interrupt Service Routine)에서 먼저 눌러진 버튼의 신호를 처리하기 전에 다음 버튼을 누르면 어떻게 됩니까? 이러한 점검은 통상적으로 수작업을 통해서 이루어지며, 정확한 입력 방법을 발견해 내기까지 여러 번 시도가 필요할 수도 있지만, 사람은 이러한 작업을 수행하는 데에 있어 믿을 수 없을 정도의 솜씨를 발휘하기도 합니다. 

품질 관리에서 흔히 하는 이야기 중의 하나가 개발이 제대로 진행되고 있는지 “일찍, 자주 테스트 하라”입니다. 이를 통해 개발 초기에 오류를 수정할 수가 있으며, 이는 상당한 시간과 금전을 절약할 수 있게 해 줍니다. IBM의 추산 결과, 요구 사항 수집(Requirements Gathering) 단계에서는 버그 하나를 고치는 데에 100 달러가 들지만, 일반 시험 및 교정 단계에서는 개당 1,500 달러가 소요되며, 생산 단계에서는 10,000 달러가 소요됩니다. 그리고 조직의 규모가 커질수록, 이러한 액수는 그에 맞추어 늘어나게 됩니다.[6] 그러니, 가급적 많은 버그를 일찍 잡아내는 것이 중요한지 아실 수 있을 것입니다. 바로 여기에 착안한 것이 시험 중심 개발(Test-Driven Development, TDD)입니다. TDD에서는 개발 사양에서 벗어나는 상황에 대한 시험을 실시하며, 설계가 시작되면서 동시에 이러한 시험도 시작됩니다. TDD의 주요 개념은 코드를 작성/수정해 가면서 이러한 요구사항에 기반을 둔 시험을 통과하도록 하는 것입니다. 이 방식을 적용할 경우, 코드의 작성, 시험, 반복이 매우 짧은 주기로 실시하고 다음 단계로 넘어가지만, 계속해서 첫 번째 모듈에 대한 시험, 그리고 다른 모듈과의 통합에 관한 시험을 진행하는 것입니다. 여기서 주안점은 초기에 개발의 속도를 늦춤으로써, 후반부에는 매우 빠른 속도로 개발을 할 수 있게 하는 것입니다. 

빠른 개발의 첩경은 바로 코드 품질 

요약하자면개발의 속도를 높이고 싶다면 가장 먼저 해야  일은 코딩 표준을 통해 코드 품질을 높이는 것입니다 가지 다행스러운 일은 이러한 과정을 도와주는 툴들이 존재한다는 것입니다따라서 개발자는 에러 투성이로 대충 코딩을  결과 발생한 버그를 빠르게 찾아 제거할 수가 있습니다둘째로코드의 설계 시에 확장성을 고려하고모듈간의 예속을 줄여 쉽게 변경과 관리확장이 가능하도록 하는 것입니다마지막으로자동화 테스팅의 효과성에 대해 현실적으로 접근할 필요가 있으며모든 테스트를 완전히 자동화하는 것은 불가능하다는 것을 명심해야 합니다이것은 처음에는   많은 시간이 걸리는 일이지만장기적으로는 그에 맞는 효과를 기대할  있습니다. 

 

작성: Shawn Prestridge산업 프로필  US FAE  관리자, IAR Systems 

참고문헌