ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 15. 소프트웨어 설계
    잡談/DO-178 번역 2019. 3. 18. 14:42

     

    DO-178B에 있어서 소프트웨어 설계는 매우 융통성이 있다. 라이프사이클이 어떻게 수행되어야 하는지, 어떤 문서들이 합쳐져야 하는지 혹은 따라야할 방법론이 무엇인지를 요구하지 않는다. 그런 융통성은 당신이 자신의 방식을 정의하도록 만들어 준다. 당신은 유스케이스(Use Case)를 사용할 것인가? UML을 사용할 것인가? 다이어그램으로 구조 차트와 데이터를 사용할 것인가? 구조화된 문법을 사용할 것인가? DO-178B(아래 그림에서 보이는 것처럼) 설계에 대해서 네 가지 핵심 특성을 기술하라고 말한다.

     

     

    소프트웨어 설계 개요

     

    DO-178B는 설계/문서에 융통성을 제공한다

     

    네 가지 핵심 특성들:

     

    하위레벨 요구사항

    인터페이스 정의

    데이터 플로우

    컨트롤 플로우

     

     

     

    DO-178B는 이런 융통성을 제공할까? DO-178B를 누가 작성했는지 기억하라. 바로 산업계와 정부부처 사람들의 조합이다. 이들은 모두가 항공전자 안전성에 대한 공통된 기반을 찾아내고 문서를 통해서 그것을 체계화하려고 하는 한가지 목적으로 모였다. 그 문서가 DO-178B이다. 그리고 하드웨어에 대한 DO-254도 비슷하게 구상되고 정의되었다. DO-178B 미팅에서 각 회사는 각자 자신들의 회사에서 사용하는 방법론을 적용하기를 선호했다. 하지만 어떤 회사도 주도하지 못했고 많은 회사들이 존재하고 있었다. 최종 결과는 항공전자장비를 어떻게 개발하는지, 특히 설계 영역에 있어서 많은 융통성을 제공하는 것이었다. 결국 항공전자 설계에는 그런 다양성과 진화가 있으며 이런 융통성은 현명한 선택이었다.


    역주) DO-178이 융통성을 갖게 된 배경을 설명하고 있다. DO-178이 만들어진 배경이기도 한데 어찌 보면 당연한 일이다. 애플이 세계 1위 휴대폰 기업이라고 삼성이 애플과 동일한 방법으로 휴대폰을 개발해야 하는 것은 아니며 그럴 수도 없다. 그런 관점에서 DO-178 가이드라인이 만들어졌고 그에 따른 융통성을 가지게 되었다. 그리고 결과적으로 그것은 모든 기업이 DO-178 가이드라인을 준수할 수 있게 만들어 주었다.

     

    너무 멀리 가기전에 멈추는 것에 관한 주의를 기억하라. 어쨌든 당신은 최종 요구사항 분해가 하위레벨 요구사항에 해당한다고 말해야 한다. 어떤 사람들은 상위레벨 요구사항이 소프트웨어 요구사항 스펙에 있다고 말한다. 하위레벨 요구사항은 아키텍처 혹은 설계 구문에 있다고 말한다. 당신이 그것을 무엇이라고 하든 상관없다. 진실은 현실 세계와 같아서 인간은 경계가 지어지는 것에 편안함을 느끼지만 실제 결정되는 경계는 때로는 회색빛이다. 만약 당신이 DOORS와 같은 요구사항 관리툴을 사용하는 경우에는 문서로 경계가 지어지지 않는다. 당신은 상위레벨 설명을 가지고 있다. 또 다른 분해된 설명이 있고 좀 더 분해된 또 다른 것이 있다. 마지막과 중간의 설명 혹은 요구사항의 흐름이 끝나는 어떤 곳이든 하위레벨 요구사항으로 불릴 수 있다.


    역주) 설명이 복잡한데 결국은 요구사항을 작성할 때 상위레벨부터 시작해서 점차 세분화하겠지만 너무 많은 단계를 거치지 말라는 것이다. 결국 최종 단계로 정의한 요구사항을 가지고 소스코드를 작성할 수 있으면 된다. 그리고 그렇게 정의되는 최종 단계 요구사항을 하위레벨 요구사항이라고 하는 것이다. 아마도 단계에 대한 부분은 회사들마다, 프로젝트마다 제각각이겠지만 지금까지 역자가 경험한 바로도 그렇고 대체로 상위레벨 요구사항과 하위레벨 요구사항 두 단계로 충분하다.

     

    스스코드를 통해서 설계를 한 번에 제대로 구현할 수 있을 만큼 충분히 상세하게 작성될 수 있는 레벨로 내려가는 한 그것을 무엇으로 부르든 상관없다. 일반적으로 이것은 하나의 요구사항이 15 ~ 20라인의 코드를 커버한다는 의미이다. 하지만 설계에는 하위레벨 요구사항과 인터페이스 정의가 설명되어야 한다. 하드웨어와 소프트웨어 사이 그리고 내부적으로는 외부 인터페이스와 내부 인터페이스 정의가 있다. 예를 들어 만약 여러 개의 태스크, 여러 개의 프로세스, 여러 개의 클래스와 여러 개의 기능들이 있다면 그들 간의 인터페이스는 어떻게 나타내는가? 버스 인터페이스는 무엇인가? 메모리와는 어떻게 인터페이스 되는가? 운영체제와는 어떻게 인터페이스 되는가? 설계 구문과 설계 데이터 정보에는 데이터 플로우과 컨트롤 플로우뿐만 아니라 내부와 외부의 모든 인터페이스가 완전하게 정의될 필요가 있다.

     

    최상위 레벨의 설계 표현과 관련된 하위레벨 설계 구문이 필요한가? 아니, 필요하지 않다. 그것은 군에서 일반적으로 항공전자시스템의 설계를 문서화하는, 예를 들면 상위레벨 설계 문서와 분리된 하위레벨 설계문서로 구분하는 방법이다. 하지만 군은 이제 거의 전체적으로 DO-178B와 그것이 제공하는 설계문서에 대한 융통성을 따르고 있다. 마찬가지로 군은 비록 느린 흐름이긴 하지만 DO-254를 점차 적용하고 있으며 저자는 다음 몇 년 후에는 DO-254가 군 항공전자 하드웨어에 사실상 의무화될 것이라고 믿는다. 하지만 당신의 설계를 문서화하는 최종 결과는 변하지 않을 것이다. 오늘날 대부분의 항공전자 회사들처럼 당신은 요구사항을 공식화한 후 그리고 코드를 구현하기 전 설계를 문서화할 것이다. 이 문서는 여기에 기술된 것처럼 설계문서이다.


    역주) 저자가 이 글을 쓴 시기가 대략 2002년 이전이라고 보고 2018년을 기준으로 보면 벌써 15년이 훨씬 넘는 시간이 흘렀다. 그렇다면 저자의 장담처럼 DO-178DO-254가 군에서 주류가 되었을까? 미국이나 유럽에서는 어떤지 모르겠지만 적어도 한국에서는 아직 그런 수준은 아닌 것으로 보인다. 그나마 한국에서 DO-178이 조금씩 그 중요성을 인정받는 분위기가 형성되고 있는 정도이다.

     

    우리나라만 본다면 저자의 주장이 반정도는 맞아 들어가고 있는 것 같다. 적어도 군 감항당국이 DO-178에 대해서 요구하는 사례가 점점 늘어나고 있는 게 사실이다. 물론 미국의 DO-178과 완전히 동일하지는 않고 준용의 관점에서 커스터마이징된 형태로 적용되고 있다.

     

    우리들 대부분은 버블차트에서 데이터 플로우를 정의한다. 혹은 그런 식으로 데이터 플로우와 설계를 문서화하는 것을 배웠다면 데이터 사전을 가지고 있을 지 모른다. 하지만 당신은 데이터 플로우를 정의하기 위해서 UML 프로세스와 같은 다른 방법론을 사용할 지 모른다. 그러나 데이터 플로우는 기본적으로 순차적인 프로세스내에서 소프트웨어의 한 부분에서 다른 부분으로 이동하는 정보이다. 비동기적인가? 그리고 어떻게 앞뒤로 왔다갔다하는가? 소프트웨어 컴포넌트들 사이에 전달하려고 하는 의미는 무엇인가? 각각의 트랜젝션에 적용하는 데이터 컨텐츠와 형식은 무엇인가? 이러한 것들이 당신의 설계 문서가 대답해야 할 데이터 플로우에 관한 질문들이다.


    역주) 역자는 아직 저자가 말하고 있는 데이터 플로우에 대한 개념을 명확하게 파악하고 있지는 못한 상태이다. 설계에 포함되는 데이터가 정확하게 정의되고 데이터를 중심으로 한 기능과 프로세스가 정확하게 설계되어야 하며 소스코드가 그에 따라서 제대로 구현되었다는 것을 보여줄 수 있어야 한다고 이해하고 있는 정도이다. 이 부분은 실제 현장에서는 VectorCAST와 같은 커버리지 분석툴의 도움을 받아서 컨트롤 플로우와 함께 결과를 얻고 분석하게 되는 것으로 알고 있다. 기회가 된다면 실제 사례를 가지고 다시 공유하겠다.

     

    컨트롤 플로우와 데이터 플로우는 소프트웨어의 분석과 스펙에 관련된 구조적 방법이다. 컨트롤 플로우는 Call Tree에 의해서 표현되는 것처럼 아키텍처 레벨로 보여줄 필요가 있다. 그것은 계층적으로는 최상위에서 최하위로 연속적으로는 좌측에서 우측으로 흘러간다. 그것이 아주 흔한 형태이다.

     

    완전한 컨트롤 플로우를 제공하는 구조 차트 이면에는 하나의 방법론이 존재한다. 하지만 어쨌든 당신은 당신만의 방법론을 명시하고 거기에 따라서 컨트롤 플로우를 표현해야 한다. 실시간 운영체제에서처럼 복합 프로그램에 대해서 컨트롤 플로우상의 계층을 단계별로 따라갈 수 있어야 한다. 어떤 프로그램이 어떤 순서로 들어오고 누가 먼저 인터럽트를 받게 되는가? 그러한 아키텍처 컨트롤 플로우의 모든 것들이 또한 표현될 필요가 있다.


    역주) 데이터 플로우와 마찬가지로 컨트롤 플로우 역시 VectorCAST와 같은 도구의 힘을 빌려야 하는 것으로 알고 있다. 실제로 데이터 플로우, 컨트롤 플로우를 직접 손으로 하나하나 그리고 분석하는 것은 거의 불가능하다고 알고 있다. 최소한 VectorCAST와 같은 툴을 통해서 나온 결과물을 가지고 실제 소스와 직접 매칭하면서 비교 분석할 수는 있어야 할 것이다. 역자는 아직 그런 작업까지 진행해 보지는 못했는데 이 역시 기회가 되면 실전사례를 공유하겠다. (참고 포스팅: 7. DO-178과 커버리지 분석 – Data / Control Coupling (1))

     

     

    요구사항 vs 설계

     

    하위레벨 요구사항: 이것이 무엇일까?

      


    상위레벨 요구사항과 설계의 중복 = 하위레벨 요구사항

     

     

     

    하위레벨 요구사항은 상위레벨 요구사항과 설계 정보 사이의 어딘가에 있다. 당신이 그것으로부터 코드를 작성할 수 있을 때 당신은 하위레벨 요구사항을 가진 것이고 그것이 충분히 분해되었다는 의미이다. 설계 구문을 하위레벨 요구사항이라고 부르지 않도록 주의하라. 만약 그렇게 하게 되면 많은 불필요한 시험을 하는 결과를 초래하게 될 것이다. DO-178B당신의 시스템은 당신이 설계한대로 그리고 안전하게 동작하는가?”라는 식으로 관심을 가지는 것에 비해서 당신이 어떻게 설계했는지에 대해서는 그렇게 많이 신경 쓰지 않는다.


    역주) 일반적으로 DO-178에서는 하위레벨 요구사항을 설계문서에 작성하게 된다. 따라서 설계에 대해서 설명하는 수 많은 내용들이 함께 포함되는데 그렇다면 그런 설명과 요구사항을 어떻게 구분할 것이냐가 중요하다. 모든 일이 그렇지만 경험이 없는 상태에서는 이를 구분해서 작성하는 것이 많이 어렵다. 개념도 잘 이해를 못한 상태에서 더구나 영어로 작성해야 한다. 어쩔 수 없이 시행착오와 연습이 필요한 부분이다. 그리고 DER감사가 아닌 컨설팅을 받아야 할 부분이다. 물론 그에 따른 비용 지출은 필수이다.

     

     

    인터페이스 정의

     

    소프트웨어 설계 문서에 모든 인터페이스 정의를 포함

     

    외부, 하드웨어를 포함

    내부, 모든 소프트웨어를 포함

     

    BSP

    RTOS

    어플리케이션

    라이브러리

    드라이버


     

     

     

    인터페이스 정의, 외부 그리고 내부. 여기에 기술된 인터페이스는 CPU 내부에서 처리되는 것이다. 구체화되고 문서화되어야 하는 인터페이스는 위의 다이어그램에서 보여지듯이 소프트웨어 컴포넌트들 간의 모든 인터페이스를 포함한다. 이것은 소프트웨어의 이러한 컴포넌트들 각각과 당신의 어플리케이션 소프트웨어 간의 인터페이스, 그리고 당신의 소프트웨어 내부의 모든 인터페이스를 포함한다. 우리는 이런 질문을 여러 번 받는다. “하지만 그것은 제 소프트웨어입니다. DO-178이 왜 저의 내부적인 인터페이스까지 신경을 쓰나요?” 그 답은 간단하다. “, 그것은 당신의 내부 소프트웨어가 맞습니다. 하지만 내일이 되면 그것은 다른 누군가에 의해서 시험되고, 유지되고 변경될 것입니다. 그 누군가는 그것을 완전하게 이해할 수 있어야겠죠.”

     

    컨트롤 플로우는 모듈간의 컨트롤 전이가 어떻게 이루어 지는가에 대한 기술이다. 기본적으로 그것은 Call Tree이다. 모듈간의 관계는 무엇인가? 누구 누구를 호출하며 언제 그리고 어떤 조건하에서 호출하는가? 계층적으로 누가 하위의 모듈을 컨트롤하는가? 언제 호출되고 초기화되는가? 언제 순서대로 이어지는가? 컨트롤 플로우와 관련된 이러한 질문들이 설계문서에 포함된다.

     

     

    데이터 & 컨트롤 플로우

     

    컨트롤 플로우는:

     

    모듈간의 컨트롤 관계에 대한 설명

    모듈이 활성화되는 조건에 대한 설명

    모든 소프트웨어 모듈을 포함

     

    따라서: Call Tree가 모든 입력 파라미터와 함께 모든 소프트웨어 모듈을 보여줄 것이다.

     

    데이터 플로우는:

     

    설계내에서 조작되는 데이터에 대한 설명

    각각의 데이터에 대한 소스와 목적지의 설명

    모듈간에 교환되는 모든 데이터를 포함

     

    따라서: 데이터 사전이 형식, 범위 그리고 초기값과 함께 모든 데이터를 리스트화할 것이다.

     

     

     

    당신의 설계를 작성할 때 모든 소프트웨어 모듈을 포함하는 것을 확인하라. 데이터 플로우는 데이터가 시스템 소프트웨어를 통해서 지나가기 때문에 설계 내에서 다루어지는 데이터의 설명을 제공할 것이다. 외부 데이터의 프로세싱 스트림으로의 흐름을 설명하는 소프트웨어 문서에 컨트롤 플로우 정보를 포함하라. 실행 레벨로의 다음 단계를 포함하는 계층적인 레벨을 정의하라. 위의 데이터 플로우 정보를 당신의 소프트웨어 설계문서에 포함함으로써 당신은 DO-178B의 의도를 만족할 것이다.

     

     

    컨트롤 플로우

     

    소프트웨어 설계 문서에 컨트롤 플로우를 포함

     

    프로세싱 스트림으로의 외부 데이터의 흐름

    프로세싱 스트림내에서의 내부 데이터의 흐름

    모든 모듈에 대한 모둘 활동을 포함

     

     

    데이터 플로우

     

    소프트웨어 설계 문서에 데이터 플로우를 포함

     

    프로세싱 스트림으로의 외부 데이터의 흐름

    프로세싱 스트림내에서의 내부 데이터의 흐름

    모든 데이터 아이템에 대한 소스와 목적지 정보를 포함

    데이터 사전을 포함하거나 참조

    데이터 커플링 특성을 분석하기 위한 충분한 상세설명을 포함

     

     

     

    역주) 데이터 플로우와 컨트롤 플로우에 대한 내용이 계속해서 나오고 있다. 사실 이 두 가지를 이렇게 글로 설명하는 것에는 한계가 있다는 생각이다. 개념적으로만 이해를 하고 실제적인 부분은 가능하다면 툴을 통한 실제 결과를 보는 것이 가장 빠른 방법이라고 생각된다. 그런 의미에서 한컴MDS나 모아소프트, 슈어소프트 등에서 진행하는 관련 툴교육에 참석하는 것도 한가지 방법이 될 것이다.

     

    어쨌든 여기서 나오고 있는 데이터 플로우와 컨트롤 플로우는 결과적으로 설계를 제대로 했는지, 그 설계를 바탕으로 소스코드가 제대로 구현되었는지를 확인할 수 있는 데이터이다. 구체적인 방법론에 있어서는 다양한 방법이 존재할 수 있다. 구현하고자 하는 소프트웨어의 특성, 언어적인 특성, 아키텍처의 구성 등에 따라서 또한 업체나 개발자에 따라서도 달라질 수 있고 그 표현방식도 천차만별이다. 정해진 하나의 방법이 있는 게 아니라는 것이다. 저자가 이야기하는 부분도 그 여러 가지 방법 중 일부를 개념적인 수준에서 소개하는 것이지만 사실 개념적으로만 보자면 관련된 대부분의 내용이 포함되었다고 할 수 있다.

     

    실제 진행 시에는 소스코드와 시험케이스 및 절차서를 이용하여 툴을 통해서 현재의 결과를 추출하고 그 결과를 설계문서와 분석하는 형태로 진행될 수 있는 것으로 알고 있다. 앞서 말한 것처럼 언젠가 기회가 되면 이 부분만 따로 주제를 잡아서 정리를 해볼까 한다(참고 포스팅: 7. DO-178과 커버리지 분석 – Data / Control Coupling (1))

     

     

    설계 결합도(Coupling) 및 응집도(Cohesion)

    (좋은 그리고 나쁜 콜레스테롤 같은)

     

    응집도(좋음): 모듈 내에서 서로 관계되는 정도

     

     

     

     

    결합도(나쁨): 기능의 상호작용이 의도하지 않은 부작용을 일으킬 수 있음

     

     

     

    소프트웨어 설계는 소프트웨어 엔지니어링의 두 가지 “C”를 고려해야 한다. 바로 응집도(Cohesion)과 결합도(Coupling)이다. 한 가지 기억방법은 당신의 혈류에 있는 콜레스테롤과 관련된 것이다. 한 가지는 좋은 것이고 다른 것은 나쁜 것이다. 당신은 하나(희망컨데, 좋은 것)를 증가시키고 반면에 다른 것은 감소시키기를 원한다. 소프트웨어 설계자도 비슷하다. 결합도를 최소화하는 반면에 응집도를 최대화하기를 원한다. 사람들은 모듈들이 타이트하게 결합된 것을 원하지 않지만 만약 당신이 당신의 표준에 그것을 언급하고 있다면 결합도를 어떻게 정의할 지를 구체화해야 한다. 응집도도 마찬가지여서 당신은 하나의 파일(모듈) 내의 모든 함수들이 밀접하게 연결된 기능을 수행하기를 원한다.


    역주) 설계의 관점에서 결합도(Coupling) 와 응집도(Cohesion)는 모듈과 관계된 용어이다. 중요한 차이점은 결합도는 모듈 간의 관계이고 응집도는 모듈 내의 관계라는 점이다. 소프트웨어는 재사용성이 아주 중요하다. 그래서 외부의 영향을 최소화한 독립적인 구현에 초점을 맞춘다. 그런 의미에서 본다면 모듈간의 관계를 보여주는 결합도는 낮은 것이 좋다. 모듈간의 영향이 최소화 되는 것이고 그런 상태에서는 모듈을 어느 곳이든 자유롭게 사용할 수 있다. 반대로 응집도는 높을수록 좋다. 응집도가 높다는 것은 모듈이 내부적으로 아주 긴밀하게 돌아가도록 잘 구현되었다는 것을 보여주는 것이다.

     

     

    소프트웨어 코딩

     

    DO-178B는 구현(코딩)의 융통성을 제공한다

    사실상 어떤 언어, 컴파일러 혹은 스타일도 가능하다

    코딩 표준을 준수할 것을 요구한다.

     

     

     

    언어를 어떻게 사용하는가에 유의하라. 사람들은 서로 다른 스타일을 가지고 있다. 하지만 포인터의 정의와 개수 그리고 중첩루프의 깊이에 있어서는 확실해야 한다. 루프 컨트롤 변수에 대해서 그것이 어떻게 초기화되는지 그리고 그 값이 얼마나 클 수 있는지를 구분하라. 데이터 타입이 어떻게 정의되고 사용되는지를 구분하라. 추상화 그리고 객체 정의 규칙을 구분하라.

     

    배열의 길이를 검토하라. 얼마나 크게 될 수 있나? 표준 배열 크기는 무엇인가? 동적인가? 항상 고정되어야 하나? 이 모든 질문들이 답변되어야 한다. 하지만 당신이 코딩을 할 때 DO-178B에는 여러 가지 이슈들이 있다.


    역주) DO-178에서는 코딩룰을 따를 것을 요구한다. 대신 코딩룰은 특별히 정해진 것은 없다. 회사 혹은 팀내에서 알아서 정하면 된다. 다만 그 룰이 무엇인지 DER이 확인할 수 있어야 하고 개발자들이 실제로 그에 따라서 코딩을 하는 지 확인이 되어야 한다. 사실 그 부분이 가장 어렵다. 개성이 강한 개발자들의 특성도 있고 일반적으로 다들 알아서 잘 하겠거니 묵시적으로 넘어가는 부분이다 보니 코딩룰을 정해놓고 무조건 거기에 맞추어 코딩을 하는 그런 문화 자체가 없는 경우가 대부분이다. DO-178 인증을 받으려면 이런 습관도 고칠 수 있어야 한다. (참고 포스팅: 23. 소프트웨어 개발 표준문서 – SRS, SDS, SCS)

     

     

    소프트웨어 코딩 이슈

     

    Dead Code

    비활성화된 코드

    코드 복잡도

    단위시험

     

     

     

    당신이 반드시 기술해야 할 몇 가지 코딩 이슈들이 있다. DO-178B는 그것들의 주관적인 면 때문에 가볍게 다루고 있다. 하지만 우리는 FAA와 성공적으로 인증된 프로젝트들은 다음과 같은 네 가지 주요 소프트웨어 코딩 이슈들을 지속적으로 다루는 것을 발견했다. 1) Dead Code 2) 비활성화된 코드 3) 코드 복잡도 4) 단위시험이 그것들이다.

     

     

                                             Dead Code vs 비활성화된 코드

     

    Dead Code: 비행 중에 절대 수행되지 않으며 존재할 이유가 없는 코드

     

    비활성화된 코드: 비행 중에 절대 수행되지 않으나 존재할 이유가 있는 코드

     

     


     

    Dead Code, 비활성화된 코드, 코드 복잡도 그리고 단위시험. 코드가 간단할수록 덜 복잡하고 시험, 검증, 유지하기 쉽다는 것은 잘 알려져 있다. 에러도 발견하기가 더 쉽다. 복잡도는 대게 중첩된 결정문, 반복의 횟수 그리고 goto문과 같은 코드로부터의 잠재적 연속성에 대한 측정이다.

     

    단위시험. 그런데 DO-178B는 공통된 관행으로 보이는 단위시험에 대해서 절대 직접적으로 이야기하지 않는다. 단위시험은 DO-178A의 잔재로써 반드시 나쁜 관행이라고 생각할 필요는 없다. 사실 단위시험은 바람직한 것이고 당신의 소프트웨어 개발 프로세스의 중요한 부분이 되어야 한다. 순수하게는 우리는 모든 모듈이 올바로 동작하는지를 확인하고 싶어한다. 하지만 그것은 DO-178B를 준수하는 관점에서 당신의 소프트웨어에 대한 최선의 접근은 아닐 지 모른다. 그 이유는 단위시험은 주관적이기 때문이다. DO-178B에서 중요한 것은 객관성과 결정론이라는 것을 기억하자. 당신은 좋은 예술과 좋은 음악을 정의할 수 있는가? 그것은 상대적이다. 그렇지 않은가? 단위시험도 마찬가지다. 우리 모두는 그것이 도움이 되고 중요하며 그것을 해야 된다는 것을 알고 있다. 하지만 조직의 관점에서 단위시험을 객관적이고 일관성있게 정의하고 구현하며 유지하는 것은 어렵다. 그런 다음에는 그것들이 엄격하게 문서화되어야 하는가? 리뷰되어야 하는가? 형상관리되어야 하는가? 감사되어야 하는가? 대신 DO-178B는 단위시험 이후의 공식적인 검증에 집중한다.

     

    여기에 지금까지 당신의 DO-178B에 대한 지식을 시험할 질문이 있다. 그리고 그 답은(당연히) DO-178B 내에서 혹은 어떤 관련된 문서에서도 발견되지 않는다. 그 질문은 만약 당신이 독립된 검증이 필요한 레벨 A 혹은 B 프로젝트를 수행하고 있다면 개발자가 만든 단위시험을 동일한 소프트웨어의 공식 시험에 대한 기준으로써 독립적인 재사용을 하는 것이 허용되는가?” 가만 생각해 보면 시험자가 개발자의 단위시험을 재사용 하는 것이 매우 편리하고 효율적일 것이다. 정확한가? 그리고 그것은 시험자가 가질 수 있는 어떤 가정을 최소화할 것이다. 정확한가? 글쎄, DO-178B는 효율성이 아니라 정확성에 관한 것이다. 만약 시험자가 코드 작성자가 만든 단위시험을 재사용한다면 그 시험자는 단지 개발자에 의해서 만들어진(아마도 실수였을) 가정을 공식화하는 것일 뿐이다. 따라서 앞에서 나온 질문에 대한 답은 아니오로 바꾸어야 한다. 대충 할 수 있지 않을까? 마트의 좀 도둑은 때로는 들키지 않고 넘어가기도 한다. 이런 것처럼 그것도 가능할 수는 있다. 하지만 그것은 잘못된 것이고 DO-178B에 반하는 것이며 절대 하면 안되는 것이다. 그것은 좀도둑질이 아니라 항공전자 소프트웨어이고 사람의 생명이 달려있다. DO-178B는 신뢰에 관한 것이지만 모두의 신뢰를 유지하기 위해 충분한 감사와 독립성을 가진다.


    역주) 단위시험이 객관적인 시험이 아니라 주관적인 시험이라는 사실은 사실 개발자들에게는 잘 와닿지 않을 것 같다. 오류가 없는 완벽한 코드를 만들기 위해서 정말 손이 많이 가는 단위시험을 한다는데 그건 믿을 수 없어라고 하며 이렇게 평가절하를 하다니. 다들 아는 것처럼 단위시험은 소스를 기반으로 한 시험이다. 그런데 만약 소스 자체가 잘못 구현되어 있다면? 그냥 개발자의 상상 속에서 이것 저것 다 들어가 있는 소스라면? 거기에 기반한 단위시험이라고 하는 것은 잘못된 소스 혹은 개발자의 상상을 확인하는 과정에 지나지 않는다. 결론적으로 DO-178B에서는 요구사항에 기반한 시험이 객관적인 시험이다.

     

    Dead Code는 비행 중에는 절대 수행되지 않으며 존재할 이유가 없는 코드이다. 그것은 시스템에서 제거되어야 한다. 다른 말로 하면 당신이 요구사항 혹은 파생 요구사항으로 직접 연결할 수 없다면 그것은 Dead Code이다. 만약 코드 내에 잘못된 포인터나 실수가 어딘가 있다면 Dead Code가 실행될 가능성이 있는가? 그 답은 그렇다이고 가능하며 또한 바람직하지 못한 것이다. 만약 거기에 있을 이유가 없다면 거기에 있으면 안된다. 간단하다. 하지만 어떻게 거기에 있게 되었을까? Dead Code에 대한 두 가지 공통된 원인이 있다.

     

    개발자들은 때때로 개발 프로세스 동안에 코드를 가지고 실험을 한다. 그 결과는 몇 차례의 진전이 된 후에는 그들 작업의 일부가 더 이상 프로그램과 관련이 없어지게 되는 것이다. 하지만 Dead Code는 다른 사람들에게, 심지어 개발자조차도 일정 시간이 지나고 나면 그 코드가 이유가 있어서 거기에 있는 것처럼 가정하게 만들기 쉽기 때문에 혼동을 줄 가능성이 높다. 그래서 상용 제품을 만드는 큰 규모의 소프트웨어 회사라면 다들 알고 있듯이 그것은 남아있게 되고 유지에 있어서 악몽으로 다가온다.


    역주) Dead Code가 생기는 첫 번째 원인을 말하고 있다. 한마디로 개발자가 코드를 작성하면서 시험을 위한 테스트 코드를 작성했다가 시험이 끝나고도 그 테스트 코드를 삭제하지 않는 경우가 있다는 것이다. 이런 경우는 아주 흔하다. 특히나 개발자들은 그 테스트 코드가 기존 소스에 영향을 주지 않을 것이라는 막연한 믿음(?)을 가지는 경우가 많다. 그러니까 그냥 두고서는 신경을 꺼버리는 것이다. 사람이 하는 일이므로 이런 실수가 있을 수 있고 테스트 코드로 인해서 생각지 못한 동작이 실행될 수도 있다. 비행 중에 이런 일이 일어난다고 생각해 보자. 잘못하면 그 비행기가 추락해서 수 많은 사람의 목숨을 잃게 할 수도 있는 것이다. 바로 그 테스트 코드때문에.

     

    또한 컴파일러는 일반적으로 당신의 요구사항의 일부가 아닌 코드를 추가한다. 컴파일러 개발자들은 단지 당신의 소스 코드 구문에 따라서 어떤 가정을 만들고 커버가 필요하기 때문에 적은 양의 코드 세그먼트를 추가할 것이다. 하지만 이것이 엄격한 의미에서의 Dead Code는 아니다. 당신의 분석(그것이 절대 수행될 수 없다는 것을 확인할 구조적 커버리지를 수행한 후)이 그것은 제거될 수 없으며 또한 절대 활성화되지 않을 것이라는 것을 알려주기 때문에 오히려 그것은 비활성화된 코드로 불린다. 그런 코드가 더해지면 컴파일러가 어떻게 동작하고 무엇이 더해지는 지를 인지하라. 레벨 A에서 당신은 object-to-source 비교 그리고 컴파일러가 이런 여분의 코드를 추가했다는 것을 보여주게 될 것이다.


    역주) 컴파일러는 일반적으로 소스코드를 바이너리로 만드는 과정에서 최적화를 하게 된다. 사람이 만든 소스 코드를 컴파일러가 최적화함으로써 코드의 양도 최대한 줄이고 실행 속도도 높일 수 있는 장점이 있다. 컴파일러 옵션을 최적화로 설정하면 이런 결과가 생길 수 있다. 따라서 컴파일러 옵션을 최적화하지 않도록 하면 최적화는 일어나지 않을 수 있다. 실제로 DO-178 인증을 받는 소프트웨어는 가급적 최적화 옵션을 사용하지 않는 것이 좋다.

     

    비활성화된 코드는 비행 중에는 절대 수행되어서는 안되지만 거기에 있을 이유, 그래서 거기에 있어야 하는 정의된 요구사항을 가지고 있다. 그것은 항공기에 탑재되어 비행을 하지만 절대 수행되어서는 안된다. 하지만 잠재적으로는 실행될 수도 있다. 따라서 그것이 비활성화된 상태라는 것을 증명하는 것이 중요하다. 예를 들어서 핀설정과 같은 비활성화 메커니즘이 있을 수 있다.

     

    레벨 A 혹은 B에 대해서는 한 가지 비활성화 방법으로는 아마도 충분하지 않을 것이다. 자체적인 문제로 핀설정 자체가 동작하지 않을 수도 있다. 해당하는 코드는 비활성화되더라도 그 제품에 대한 위험성의 설계 보증 프로세스를 만족해야 한다. 따라서 비활성화된 코드라도 시험되어야 한다.

     

     

    비활성화된 코드의 존재이유

     

    유지관리를 위한 소프트웨어 (비행중에는 비활성화시킴)

    하나의 실행파일을 통해서 서로 다른 항공기의 구성, 다른 부분들은 비활성화됨

     

     

     

    여러가지 설정을 통해서 비행대대를 운용할 제품을 개발하고 있다고 하자. 항공기의 유형에 따라서 소프트웨어의 어떤 부분은 동작할 것이고 다른 것들은 비활성화될 것이다. 하지만 만약 당신이 B-747에 사용되는 코드를 B-737에 넣는다면 그 B-747 코드는 마찬가지로 시험되어야 한다.


    역주) 비활성화된 코드의 예는 육상에서 비행 전에 유지 보수를 위한 코드 혹은 시험에 사용되는 코드 등을 들 수 있다. 이런 코드들은 비행 전 육상에서 점검차원 혹은 관리차원에서 실행될 수 있기 때문에 아예 실행 자체가 안되는 Dead Code는 아니다. 하지만 일단 항공기가 비행을 시작하면 이 코드는 절대 실행되면 안된다. 또 다른 예는 하나의 프로그램을 여러 항공기를 대상으로 개발하는 경우가 있을 수 있다. 하나의 프로그램 안에 A 항공기에서만 돌아가는 코드, B 항공기에서만 돌아가는 코드가 같이 있는 것이다. 이런 경우 A 항공기에서 그 프로그램이 실행되는 동안에 B 항공기용 코드가 실행되면 절대 안된다. 이것이 보장되어야 한다. 이에 대한 대비책이 있어야 하고 그것이 안전하다는 것을 입증할 수 있어야 한다.

     

     

    비활성화된 코드 관리

    비활성화된 코드가 잘못 활성화되거나 실행된다면 어떻게 되는가?

     

    잘못된 포인터

     

    위험 레벨에 따라 완전한 DO-178B를 적용

     

    요구사항, 문서, 리뷰, 시험

     

     

     

    만약 비활성화된 코드가 실행하기 시작한다면 어떤 일이 발생할 지에 대해서 시험할 필요가 있다. 바라건데, 잘못 동작하는 경우 그것을 탐지하는 내장된 시험이 있을 것이다. 만약 메모리 관리 유닛이 메모리 할당을 탐지하지 못하면 와치독 타이머가 최종적인 오류 처리 루틴을 제공해야 한다. Path Timer이기도 한 와치독 타이머를 넣어라. 다른 말로 하자면, 실행하면서 컨트롤이 특정 모듈을 통과해야 하며 와치독 타이머는 그것이 해당 경로를 지나가면서 어떤 형태로든 영향을 받을 것을 예상한다. 그것은 매우 결정론적인 상태를 만든다.

     

    위험 레벨에 따라 완전한 DO-178B를 적용하라. 비활성화된 코드는 그 시점에서의 시스템 위험상태와 동일한 레벨이 될 필요가 있다. 단지 활성화되려는 의도가 없다고 해서 그것이 절대 활성화되지 않는다는 것을 의미하는 것은 아니다. 당신은 비활성화된 코드에 대해서 요구사항 문서, 설계 문서, 리뷰, 시험 그리고 검증이 필요하다. 다른 코드와 마찬가지로 동일한 모든 정보가 비활성화된 코드에 대해서도 생성되어야 한다.


    역주) DO-178에서는 모든 소스 코드가 요구사항과 연결되어야 한다는 점을 기억하자. 만약 연결되는 요구사항이 없다면 그 코드는 Dead Code라는 뜻이 된다. 그리고 그 코드는 반드시 제거되어야 한다. 만약 절대 지울 수 없는 소스코드가 요구사항없이 존재하는 것이 확인된다면 지금이라도 그 소스코드에 대한 요구사항이 추가되어야 한다. 물론 그 과정은 상당히 복잡해 질 것이다.

     

     

    코드 복잡도

     

    코드 복잡도, McCabe

     

    소프트웨어 품질/안전성과 관련된

    단위시험처럼 FAA에 의해서 규정받지 않는

     

    McCabe 복잡도 매트릭스:

     

    소스 함수의 복잡도에 관련된 0부터 X까지의 정수값

     

     

     

    코드 복잡도는 당신이 소프트웨어 품질과 안전성에 대해서 사용하는 표준이 되어야 한다. 단위시험처럼, 그것은 FAA에 의해서 통제되거나 요구되지는 않지만 DER들은 특히 내장된, 안전성이 중요한 코드에 대해서 보고 싶어하는 부분이다. 코드의 복잡도에 대해서 어떤 표준이 있어야 한다. 일반적인 표준은 “McCabe”인데 코드 복잡도 측정의 유명한 창시자이다. 리뷰어 혹은 시험자가 당신의 코드를 이해할 수 없다거나 혹은 중첩 루프가 너무 깊어서 따라갈 수 없다면 그것은 그 코드를 제대로 리뷰하거나 시험할 수 없을 수 있다.

     

     

    McCabe 복잡도 요인들

     

    분기문

    루프

    진입 & 진출점의 개수

    case/switch 구문

    중첩 레벨

    goto 구문

     

    최대 McCabe 값으로 8 ~ 10을 사용하고 코딩 표준에 문서화하라

     

     

    루프 내에서의 루프의 반복은 좋은 습관이 아니다. 진입과 진출점의 개수에 관해서 소프트웨어 개발 표준은 하나의 진입과 하나의 진출이어야 한다고 말한다. 하지만 당신이 항상 그것을 지킬 수 있는 것은 아니다. 그 점이 우리가 재진입 코드를 모두 알아야 하는 이유이다. 결정론적인 코드라면 당신은 재진입 코드를 가질 수 없다.

     

    case 구문은 복잡도를 높일 수 있다. case 구문 안에 Dead Code가 있지 않은가? default 구문이 그렇게 보일 지 모르지만 그것은 비활성화된 코드나 Dead Code가 아니다. 그럼 무엇일까? default 구문은 코딩 표준의 일부이기 때문에 제거할 수 없다. 코딩 표준에서는 default 구문이 존재해야 한다고 말하고 있다.

     

    사실 그것은 방어 코드 혹은 표준 코드이다. default 구문은 절대 통과하지 않기 때문에 구조적 커버리지 분석에서 절대 체크되지 않을 지 모른다. 따라서 당신은 그것에 대한 시험을 가지고 있지 않다. 이 경우 그것은 제거되어야 할 Dead Code 인가? 그렇지 않다. 그것을 분석하고 코딩 표준을 따르는지를 보라. 분석에 의한 방어 코드는 허용된다.

     

    goto 구문은 소프트웨어 개발에서 일반적으로 좋은 습관은 아니다. 하지만 당신 자신만을 위한 코드를 아주 일부만 끝부분에 따로 작성하는 경우 goto 구문도 별개로 수행된다면 때로는 유용할 수 있다. McCabe의 최대값으로 8에서 10을 사용하라. 그것은 DER에 의해서 적극 추천되고 흔히 사용되는 값이며 받아들여지는 값이다. 그것은 당신이 표준을 사용한다는 품질 표시이다. 당신이 사용하는 함수 각각에 대한 McCabe 값을 어떻게 결정할 것인가? 만약 당신이 프로젝트 내에서 무제한의 시간을 가지고 있고 자유롭게 일할 수 있다면 수동으로 할 수 있다. 하지만 그런 일은 절대 일어나지 않기 때문에 당신은 Polyspace 혹은 Green Hills 컴파일러와 같은 툴을 사용할 수 있다. 둘 다 자동으로 McCabe 값을 제공한다.


    역주) 소프트웨어 개발자들이라면 코드복잡도가 무엇을 말하는지 이해하고 있을 것이다. 복잡하지 않아야 한다는 것도 물론 잘 알고 있다. 하지만 막상 바쁘게, 정신없이 프로그래밍을 하다 보면 그런 부분을 신경쓰지 못하고 작성하는 경우가 종종 발생할 수 있다. 처음부터 신경쓰면 좋겠지만 현실적으로 코딩 단계에서 그것을 걸러내지 못하는 경우 구현된 코드를 툴로 돌려서 확인하게 된다. 위에서 Polyspace, Green Hills 제품을 이야기하고 있는데 사실 역자는 이것들을 사용해 본적이 없다. 아마도 최근에 많이 사용하는 QAC, VectorCAST, LDRA툴과 비슷한 역할을 하지 않나 싶다. 어쨌든 이런 부분은 툴이 문제라기 보다는 개발자, 혹은 관리자의 의지가 중요하고 DO-178을 진행하기 위해서는 필수이다.

     

     

    소프트웨어 재사용

     

    DO-178B는 소프트웨어 재사용을 허용하는가?

    간접적으로는, 그렇다.

     

    만약 재사용을 활용한다면 어떤 단계들이 생략될 수 있을까?

    물론 아니다.

     

    소프트웨어 재사용이 시간과 돈을 줄여주는가?

    일반적으로 그렇지 않다.

    옛날 건물을 리모델링한다고 생각해보자. “리모델링이 아주 적을 경우, 90% 정도의 베이스라인을 건드리지 않고 유지하는 경우에만 비용 효과가 있다.

     

    DO-178B 소프트웨어에 대해서도 동일하다.

     

     

    DO-178B가 소프트웨어 재사용을 고려하고 제공하는가? 구체적이지는 않지만 분명히 그렇다. DO-178B는 새로운, 주문형 소프트웨어의 탑다운 개발 관점으로 쓰여졌다. 그러나 가이드라인의 Section 12는 사전 인증된 소프트웨어의 관점에서 소프트웨어의 재사용을 허용한다. 문서와 코드를 고르고 해당 소프트웨어의 재사용 가능한 부분에 대한 계획문서에 정의된 대로 형상관리와 품질보증 프로세스를 진행하라.

     

    엔지니어들이 재사용에 관해서 이야기할 때는 코드에 대한 재사용이 아니다. 그것은 코드를 복사해 오는 것에 관한 것이다. 누군가 그것을 작성했고 당신은 리엔지니어링을 하고 있다. DO-178B는 그것에 관해서 이야기하지 않지만 당신은 리엔지니어링 프로세스를 정의하고 그것을 준수할 수 있다. 재사용을 활용한다면 코딩 단계는 확실히 줄어들지만 산출물에 대한 계획, 요구사항, 추적성, 리뷰, 시험 그리고 개발이라는 DO-178B 단계들을 간과해서는 안 된다. 이들 중 어떤 것도 생략될 수 없을 것이다.

     

    당신은 또한 재사용 패키지에 대한 감사 과정을 거친다. 계속해서 재사용되고 있는 COTS 패키지라고 하더라도 감사를 받아야 한다. 그것이 시간과 돈을 줄여주는가? 소프트웨어 개발 관리자로써, 우리는 일반적으로 그것이 좋은 아이디어가 아니라고 믿고 있다. 다른 사람의 코드를 이해하는 데 더 긴 시간이 걸릴 것이고 그런 다음에는 그것을 문서화하고 그것에 관한 DO-178B 요구사항을 모두 만족하게 될 것이다. 때로는 그것이 요구사항과 새로운 설계를 사용해서 처음부터 시작하는 것보다는 작성하기 쉬운 경우도 있다. 매니저들은 때때로 그것을 믿지 않지만 수 많은 항공전자 프로젝트들에 대한 우리의 경험을 통해서 관찰한 바로는 그것은 사실이다. 그래서 재사용의 습관은 때로는 개발 시간을 단축해주는 요인으로 생각되지만 DO-178B에서는 이전으로 돌아가서 요구사항, 설계, 리뷰 그리고 추적성 등의 모든 것들을 수행해야 한다는 점에서 일반적으로는 그렇지 않다.

     

    90% 정도의 베이스라인을 건드리지 않고 유지되는 경우에만 리모델링을 하는 것이 비용대비 효과적이다. 시스템이 무엇을 수행하는지를 알고 RTOS 혹은 라이브러리에서 그런 것처럼 모든 데이터를 가지고 있고 변경이 아주 적다면 그것은 효과적인 방법이다.


    역주) 여기서 말하는 리엔지니어링, 리모델링은 결국 이전에 개발된 소프트웨어를 그대로 재사용하는 것을 말한다. 소프트웨어 개발자들에게는 이상적인 일이다. 하지만 현실에서는 대부분 그렇지 않다. 시작할 때는 그냥 가져와서 그대로 사용하면 될 것 같았지만 막상 넣어서 구현하다 보면 다시 손을 대야 하는 경우가 많다. 극단적으로는 재사용으로 진행되던 부분을 모두 포기하고 다시 처음부터 시작하는 경우도 많이 발생한다. 재사용에 대한 DO-178 인증 역시 결코 쉽지않다. 재사용하는 부분에 대한 모든 요구사항이 나와야 하고 그 요구사항에 기반한 설계, 시험이 나와야 한다. 코드와도 연결될 수 있어야 한다. 연결이 안되는 부분이 있다면 그 부분을 Dead Code로 판단해야 할 지도 결정해야 한다. 결코 쉽지 않고 시간도 많이 걸릴 것이라는 점을 충분히 예상할 수 있다. 그럼에도 국내의 DO-178 인증은 소스부터 구현된 상태에서 시작하는 경우를 자주 목격하게 된다. 재사용과는 또 다른 케이스이긴 하지만 결국 위에서 말한 것과 크게 다르지 않은 과정을 거치게 된다. 현실의 벽을 만나게 되는 부분이다.

     


    '잡談 > DO-178 번역' 카테고리의 다른 글

    17. 소프트웨어 시험  (0) 2019.03.18
    16. 단위시험  (0) 2019.03.18
    14. 시스템 요구사항  (0) 2019.03.18
    13. 소프트웨어 개발 & 검증 계획  (0) 2019.03.18
    12. 형상관리 계획  (0) 2019.03.18

    댓글

Designed by Tistory.