1. 우주선 시스템을 어떻게 코딩할까? (극한 C 프로그래밍 가이드)
한줄요약: 우주선 시스템을 어떻게 코딩할까? (극한 C 프로그래밍 가이드)
시간 | 요약 |
---|---|
02:02 | 복잡한 흐름 구조를 피하라는 규칙은 코드의 가독성을 높이고 정적 분석을 용이하게 함. NASA는 goto 문과 재귀 호출을 금지하며, 단순한 for 루프를 선호함. 이러한 접근은 모든 프로그래밍 환경에서 유효함. |
03:04 | 모든 루프에는 고정된 반복 한계를 두도록 요구함. 이는 무한 루프를 방지하기 위한 조치로, 종료 조건을 명확히 설정하는 것이 중요함. 비판자들은 고정 한계가 실행 시간을 보장하지 않는다고 주장함. |
04:04 | 초기화 이후 동적 메모리 할당을 금지하고 스택 메모리만 사용하도록 권장함. 힙 메모리 사용은 메모리 관련 버그를 초래할 수 있으며, 예측 가능한 메모리 동작이 중요함. |
05:34 | 데이터 객체는 가장 좁은 범위에서 선언해야 하며, 이는 변수의 스코프를 제한하여 디버깅을 용이하게 함. 변수뿐만 아니라 함수와 타입 선언에도 적용되는 원칙임. |
07:04 | 모든 함수의 반환값을 반드시 확인해야 하며, 매개변수 검증도 신중히 수행해야 함. 이는 실행 중 발생할 수 있는 오류를 방지하는 데 필수적임. |
08:03 | C 전처리기의 사용을 제한하여 코드의 명확성을 유지하고 정적 분석을 용이하게 함. 복잡한 조건부 컴파일은 피해야 하며, 기본 원칙은 코드의 이해를 돕는 것임. |
08:32 | 포인터 사용에 대한 엄격한 제한이 있으며, 포인터는 한 번에 한 단계 이상 역참하지 말아야 함. 함수 포인터 사용은 제한해야 하며, 이는 코드의 제어 흐름을 불투명하게 만들기 때문임. |
10:04 | 모든 가능한 경고를 활성화하여 코드를 컴파일하고, 모든 경고를 해결하는 것은 소프트웨어 출시 전에 필수적임. NASA는 가장 엄격한 경고 옵션을 요구하며, 모든 경고를 오류처럼 간주하고 해결해야 릴리스할 수 있다고 명시함. |
11:04 | 나사의 Power of 10 규칙은 생명이 중요한 시스템에서 소프트웨어 신뢰성을 확보하기 위한 극단적인 조치를 보여줌. 이 규칙들은 단순함과 명확성을 우선시하여 철저한 코드 리뷰와 정적 분석을 가능하게 하며, 예측 불가능한 동작을 방지함. |
11:33 | 복잡성을 피하고 예측 가능성을 확보하며 코드에 명료함을 추구하는 원칙들은 모든 개발 환경에서 가치 있는 지침임. 이러한 원칙을 이해하고 적절히 적용하는 노력은 더 안전하고 유지 보수하기 쉬운 소프트웨어를 만드는 데 도움이 됨. |
2. 스크립트
미국 항공 우주국(NASA)의 '파워 오브 10' 코딩 규칙이라는 흥미로운 지침들을 살펴봅니다. 이 규칙들은 2006년 NASA 제트 추진 연구소의 컴퓨터 과학자 제라드 J. 홀츠만에 의해 만들어졌습니다. '파워 오브 10' 코딩 지침들은 코드의 검토나 정적 분석을 어렵게 만드는 C 언어의 관행들을 제거하기 위해 제정되었습니다. 우주 비행 임무에서는 단 하나의 소프트웨어 버그도 치명적일 수 있으며, 이는 수십억 달러의 손실로 이어질 수 있는 극한 환경입니다. 그렇기 때문에 신뢰할 수 있고 예측 가능한 코드를 작성하는 것은 단순히 좋은 습관이 아니라 필수 조건입니다.NASA 자체는 이 규칙들을 안전 벨트에 비유합니다. 처음에는 다소 제한적으로 느껴질 수 있지만, 결국에는 자연스럽게 익숙해지고 안전을 위해 필수적인 요소가 된다는 것이죠. 이러한 규칙들은 MISRA와 같은 지침을 보완하며, JPL에 보다 포괄적인 코딩 표준에도 통합되어 있습니다. 원래는 C 언어를 대상으로 만들어졌지만, 이들 중 일부에 담긴 원칙은 다양한 소프트웨어 개발 환경에서도 충분히 유용하게 적용될 수 있습니다. 그러나 우리가 곧 살펴보겠지만, NASA처럼 독특한 환경이 아닌 곳에서 이 규칙들을 엄격히 적용하는 것에는 여러 비판적인 시각이 존재합니다. 다음은 '파워 오브 10' 규칙 중 특히 유효한 여덟 가지를 살펴보겠습니다.
첫째, 복잡한 흐름 구조, 예를 들어 goto 및 재귀 등은 피하라. NASA는 코드의 제어 흐름을 단순하게 유지하도록 요구하며, goto 문, 셋 점프, 롱 점프, 그리고 재귀 호출을 명시적으로 금지합니다. 그 이유는 복잡한 제어 흐름이 코드의 흐름 그래프를 따라가기 어렵게 만들어 정적 분석이나 코드 리뷰를 매우 어렵게 만들기 때문입니다. 특히 재귀는 화성이나 달처럼 머신에 직접 접근하기 어려운 환경에서는 코드가 무한 루프로 빠질 위험이 있어 매우 위험한 것으로 간주됩니다.
2.1. 복잡한 흐름 구조를 피하라는 규칙은 코드의 가독성을 높이고 정적 분석을 용이하게 함. NASA는 goto 문과 재귀 호출을 금지하며, 단순한 for 루프를 선호함. 이러한 접근은 모든 프로그래밍 환경에서 유효함.

대신 단순한 for 루프 같은 구조가 선호됩니다. 복잡한 제어 흐름을 피하라는 원칙은 어떤 프로그래밍 환경에서도 일반적으로 유효하며, 코드의 가독성과 유지 보수성을 향상시킵니다. 많은 현대 스타일 가이드에서도 goto 사용을 권장하지 않거나 아예 금지하고 있습니다.. 재귀 금지는 큰 논쟁 지점 중 하나입니다. 비판자들은 어떤 문제들은 재귀를 사용했을 때 자연스럽고 우아하게 표현된다고 주장하며, 이를 억지로 반복문으로 바꾸려 할 경우 오히려 버그 투성이의 스파게티 코드가 만들어질 수 있다고 지적합니다. 그들이 강조하는 것은 반복문이나 재귀 함수 자체를 금지하는 것이 아니라 종료 조건이 명확히 보장되도록 만드는 것이 진짜 초점이 되어야 한다는 점입니다. 모든 루프에는 고정된 반복 한계가 있어야 하며, 이는 제어 불능 코드를 방지합니다. 무한 루프나 제어 불가능한 코드 실행을 방지하기 위해 NASA는 모든 루프에 고정된 상한 값을 두도록 요구합니다.
2.2. 모든 루프에는 고정된 반복 한계를 두도록 요구함. 이는 무한 루프를 방지하기 위한 조치로, 종료 조건을 명확히 설정하는 것이 중요함. 비판자들은 고정 한계가 실행 시간을 보장하지 않는다고 주장함.

예를 들어, 연결 리스트와 같이 종료 조건이 널 포인터인 경우에도 NASA는 반복 횟수에 대해 정수형의 엄격한 최대 한계를 설정하도록 합니다. 무한 루프를 방지하려는 개념은 어느 프로그래밍 환경에서나 매우 중요합니다. 항상 엄격한 고정 한계를 두는 것이 실용적이지는 않을 수 있지만, 종료 조건을 의식적으로 고려하고 적절한 안전 장치를 구현하는 것은 좋은 개발 습관입니다.. 제어 불능 코드를 방지하는 것이 중요하다는 데에는 이견이 없지만, 비판자들은 고정된 한계가 반드시 합리적인 실행 시간을 보장하지는 않는다고 지적합니다. 예를 들어, 반복 한계가 10의 10제곱인 루프는 이론적으로는 종료되지만 실제로는 수십억 년이 걸릴 수도 있습니다. 따라서 단순히 이론적인 종료 조건보다는 합리적이고 증명 가능한 종료에 초점을 맞춰야 한다고 주장합니다.. 둘째, 초기화 이후 동적 메모리 할당 금지, 다시 말해 힙 메모리 할당을 피할 것. NASA는 힙 메모리 사용을 완전히 피하고 스택 메모리만 사용할 것을 권장합니다.
2.3. 초기화 이후 동적 메모리 할당을 금지하고 스택 메모리만 사용하도록 권장함. 힙 메모리 사용은 메모리 관련 버그를 초래할 수 있으며, 예측 가능한 메모리 동작이 중요함.

그 이유는 use after free나 메모리 누수와 같은 많은 메모리 관련 버그들이 힙에서 비롯되기 때문입니다. 또한 가비지 컬렉터나 힙 관리 시스템은 정적 코드 분석 도구로 그 정확성을 쉽게 증명할 수 없습니다. 반면, 스택 메모리만 사용하고 그 상한을 명확히 정의하면 프로그램의 전체 메모리 사용량을 정밀하게 예측할 수 있게 됩니다. 예측 가능한 메모리 동작이라는 원칙은 자원이 제한된 환경에서 매우 중요합니다. 하지만 많은 현대 애플리케이션에서는 동적 메모리 할당이 필수적인 요소이기도 합니다. 동적 메모리 할당을 전면적으로 금지하는 것은 많은 애플리케이션에서 비현실적이라는 지적이 많습니다. 일부 비판자들은 사용자 정의된 프리스트를 사용해 동적 할당을 흉내내는 것조차도 이 규칙의 취지를 위반한다고 봅니다. 이들의 핵심은 메모리 동작의 예측 가능성에 있으며, 이를 달성하는 방법은 완전한 금지가 아니라 신중하고 명확한 메모리 관리를 통해 가능하다고 주장합니다..
셋째, 데이터 객체는 가장 좁은 범위에서 선언할 것. 이 규칙은 데이터 은닉을 강조하며, 변수는 가능한 한 좁은 스코프에서 선언하라고 권장합니다.. 자바스크립트에서는 변수 누수나 덮어쓰기를 방지하기 위해 `var`보다는 `let` 사용을 선호합니다. C#과 같은 언어에서는 접근 제한자인 `private`나 `protected` 같은 것을 사용하는 것이 권장됩니다.
2.4. 데이터 객체는 가장 좁은 범위에서 선언해야 하며, 이는 변수의 스코프를 제한하여 디버깅을 용이하게 함. 변수뿐만 아니라 함수와 타입 선언에도 적용되는 원칙임.

스코프를 제한하면 해당 변수에 접근할 수 있는 코드의 범위가 줄어들기 때문에 디버깅이 쉬워지고 의도치 않은 사이드 이펙트 가능성도 줄어듭니다. 이러한 원칙은 변수뿐만 아니라 함수나 타입 선언 등에도 적용되는 것이 이상적입니다. 이것은 모든 프로그래밍 언어나 패러다임에 보편적으로 적용될 수 있는 확고한 조언입니다. 변수의 스코프를 제한하는 것은 좋은 소프트웨어 설계의 기본 원칙 중 하나입니다.. 반환값 확인 및 매개변수 검증에 대해 나사는 `void`가 아닌 함수의 모든 반환값을 반드시 확인할 것을 요구합니다. 만약 `printf`처럼 항상 성공할 것으로 기대되는 함수의 반환값을 의도적으로 무시하려는 경우에는 그 의도를 코드 리뷰어에게 명확히 전달하기 위해 해당 반환값을 명시적으로 캐스팅해야 합니다. 핵심 원칙은 실행 중 발생할 수 있는 오류를 절대로 놓치지 말아야 하며, 어떤 형태의 확인이라도 아무 확인도 하지 않는 것보다는 훨씬 안전하다는 점입니다. 잠재적인 오류를 방지하기 위해 항상 반환값을 확인하는 습관은 모든 소프트웨어 개발에서 매우 중요한 실천입니다.
특히 외부 입력과 같은 매개변수에 대한 검증을 신중히 수행하는 것 역시 소프트웨어의 안정성을 유지하는 데 필수적입니다.. 철저한 확인이 중요한 것은 분명하지만, 모든 매개변수의 모든 측면을 완벽하게 검증하는 것은 비현실적일 수 있으며, 경우에 따라 성능에 악영향을 줄 수 있다는 비판도 있습니다. C 전처리기 사용 제한에 대해 나사는 C 전처리기의 사용을 파일 포함과 아주 단순한 조건부 매크로에만 제한합니다. 전처리기는 코드의 명확성을 떨어뜨리고 정적 코드 분석기를 혼란스럽게 만들 수 있는 코드 난독화 도구로 간주됩니다.
2.5. 모든 함수의 반환값을 반드시 확인해야 하며, 매개변수 검증도 신중히 수행해야 함. 이는 실행 중 발생할 수 있는 오류를 방지하는 데 필수적임.

특히 다양한 플래그를 이용한 복잡한 조건부 컴파일은 테스트 대상의 수를 기하급수적으로 증가시키기 때문에 강력히 지양됩니다. 현대 프로그래밍 언어들은 C의 전처리기와는 다른 메커니즘을 사용하지만, 지나치게 복잡한 코드 생성이나 조건부 논리를 피하라는 기본 원칙은 여전히 유효합니다. 이러한 복잡성은 코드의 이해와 분석을 어렵게 만들 수 있습니다.. 비전문가들도 전처리기가 암용될 수 있다는 점에는 동의하지만, 전면적인 금지에는 반대합니다. 예를 들어 조건부 디버깅 출력이나 잘 사용된 매크로는 오히려 코드의 가독성을 높이고 유지 보수에 도움이 될 수 있습니다. 핵심은 남용을 피하면서 적절하고 절제된 사용을 하는 것입니다.. 포인터 사용 제한에 대해 나사는 포인터 사용에 대해 엄격한 제한을 두고 있으며, 포인터는 한 번에 한 단계 이상 역참하지 말아야 한다고 명시합니다. 또한 함수 포인터의 사용은 가급적 제한하거나 피할 것을 권장합니다.
2.6. C 전처리기의 사용을 제한하여 코드의 명확성을 유지하고 정적 분석을 용이하게 함. 복잡한 조건부 컴파일은 피해야 하며, 기본 원칙은 코드의 이해를 돕는 것임.

이는 함수 포인터가 코드의 제어 흐름 그래프를 불투명하게 만들고 정적 분석을 어렵게 만들기 때문입니다. 이러한 규칙은 포인터 조작과 관련된 오류를 방지하기 위한 것입니다. 메모리를 신중하게 관리하고 포인터의 동작을 정확히 이해하는 것은 포인터를 사용하는 언어에서 매우 중요한 원칙입니다. 이는 안정성과 예측 가능성을 높이는 데 기여합니다.
2.7. 포인터 사용에 대한 엄격한 제한이 있으며, 포인터는 한 번에 한 단계 이상 역참하지 말아야 함. 함수 포인터 사용은 제한해야 하며, 이는 코드의 제어 흐름을 불투명하게 만들기 때문임.

이 규칙은 일부 정당한 프로그래밍 패턴을 방해할 수 있다는 점에서 논란의 여지가 큽니다. 예를 들어 수치 해석 알고리즘에서 함수 포인터를 사용하거나 추상 데이터 타입을 구현할 때 포인터는 핵심적인 역할을 합니다. 비전문가들은 이러한 패턴을 억지로 포인터 없이 구현하려고 하면 오히려 더 오류에 취약한 코드가 만들어질 수 있다고 지적합니다. 포인터의 사용을 무조건 제한하기보다는 안전하고 명확하게 사용하는 방법을 장려하는 것이 더 바람직하다는 의견입니다.. 모든 가능한 경고를 활성화하여 컴파일하고, 모든 경고는 소프트웨어 출시 전에 반드시 해결할 것. 이 규칙은 아마도 가장 보편적으로 적용 가능한 규칙일 것입니다. 나사는 가장 엄격한 수준의 경고 옵션을 활성화한 상태로 코드를 컴파일할 것을 요구하며, 모든 경고를 오류처럼 간주하고 해결해야만 릴리스할 수 있다고 명시합니다. 자바스크립트처럼 컴파일되지 않는 언어에서는 ES 린트 같은 린터를 사용해 경고를 생성하고 이를 해결하는 것이 매우 중요합니다.
이러한 접근은 개발 초기 단계에서 잠재적인 문제를 조기에 발견하게 해 주며, 전체적인 코드 품질을 크게 향상시킵니다. 컴파일러 경고 또는 린터 경고를 모두 활성화하고 이를 해결하는 것은 소프트웨어의 중요도와 무관하게 모든 소프트웨어 프로젝트에서 필수적인 실천입니다.
2.8. 모든 가능한 경고를 활성화하여 코드를 컴파일하고, 모든 경고를 해결하는 것은 소프트웨어 출시 전에 필수적임. NASA는 가장 엄격한 경고 옵션을 요구하며, 모든 경고를 오류처럼 간주하고 해결해야 릴리스할 수 있다고 명시함.

이는 코드의 안정성과 품질을 높이는 가장 기본적이면서도 효과적인 방법입니다.. 나사의 Power of 10 규칙은 생명이 중요한 시스템에서 소프트웨어의 신뢰성을 확보하기 위해 얼마나 극단적인 조치를 취하는지를 보여주는 흥미로운 사례입니다. 이 규칙들의 궁극적인 목표는 단순함과 명확성을 우선시하여 철저한 코드 리뷰와 정적 분석을 가능하게 하고, 예측 불가능하거나 치명적인 동작을 방지하는 것입니다.. 작의 위험을 최소화하는 데 있습니다.
물론 이러한 규칙을 다른 개발 환경에 그대로 적용하는 데에는 실용성과 유연성 측면에서 비판적 분석이 필요할 수 있습니다.
2.9. 나사의 Power of 10 규칙은 생명이 중요한 시스템에서 소프트웨어 신뢰성을 확보하기 위한 극단적인 조치를 보여줌. 이 규칙들은 단순함과 명확성을 우선시하여 철저한 코드 리뷰와 정적 분석을 가능하게 하며, 예측 불가능한 동작을 방지함.

하지만 복잡성을 피하고 예측 가능성을 확보하며 코드에 명료함을 추구하는 핵심 원칙들은 어떤 개발 환경에서도 매우 가치 있는 지침입니다. 우리가 작성하는 소프트웨어가 수백만 마일 떨어진 우주용 앱이 아니라도 이러한 원칙들의 배경을 이해하고 각자의 개발 환경에 맞게 적절히 적용하려는 노력은 더 경고하고 유지 보수하기 쉬운 소프트웨어를 만드는 데 확실히 도움이 될 수 있습니다.
2.10. 복잡성을 피하고 예측 가능성을 확보하며 코드에 명료함을 추구하는 원칙들은 모든 개발 환경에서 가치 있는 지침임. 이러한 원칙을 이해하고 적절히 적용하는 노력은 더 안전하고 유지 보수하기 쉬운 소프트웨어를 만드는 데 도움이 됨.

콘텐츠가 유익했다면 좋아요를 눌러 주시기 바랍니다. 업계 트렌드와 다른 관점을 골라 담아오겠습니다. 시청해 주셔서 감사합니다..
3. 영상정보
- 채널명: 개발자방16
- 팔로워 수: 7,360
- 좋아요 수: 239
- 조회수: 4,067
- 업로드 날짜: 2025-04-05
- 영상 길이: 12분 17초
- 다시보기: https://www.youtube.com/watch?v=gKWJbdtHLe4