10 правил, которые позволяют NASA писать миллионы строк кода с минимальными ошибками

http://web.eecs.umich.edu/~imarkov/10rules.pdf
  • Перевод

image
Маргарет Гамильтон стоит рядом с написанным ей исходным кодом бортового компьютера «Аполлона»


Лаборатория реактивного движения (Jet Propulsion Laboratory) — научно-исследовательский центр НАСА, ответственный за большинство беспилотных космических кораблей США. Там пишут много кода, и права на ошибку у них намного меньше, чем у обычных программистов.


В JPL пишут на Си, и на их сайте есть документ "JPL Institutional Coding Standard", описывающий жесткие стандарты кодирования внутри организации. Они напоминают правила программирования для встроенных (embedded) систем и систем реального времени, с ограниченными ресурсами. Но многие из правил эти просто принципы хорошего программирования. Ограничение сложности, максимальное упрощение для последующего чтения кода и отладки, отсутствие побочных эффектов. Мы в Хекслете постоянно говорим об этом в вебинарах и, конечно, в самих курсах. Мы считаем очень важным как можно раньше поднимать эти темы, поэтому про функции и побочные эффекты начинаем говорить в самом первом курсе «Основы программирования», который рассчитан на новичков. Это бесплатный курс, кстати, и в нем есть практика на языке JavaScript.


Спасибо хабраюзеру Boletus за важную поправку и дополнение:
В 2006 году Gerard Holzmann с коллективом сформулировал 10 основных правил для JPL в документе «The Power of 10: Rules for Developing Safety-Critical Code». Они вошли в основу нынешнего стандарта, наряду с MISRA C и другими дополнениями. Статья в Википедии.


Вот перевод этого списка.


  1. Нужно сильно ограничивать ветвления и условия. Не использовать goto, setjmp или longjmp, не использовать прямую или косвенную рекурсию.


  2. У всех циклов должен быть предел. Проверяющая программа должна иметь возможность легко доказать, что определенное количество итераций не может быть превышено. Если предел невозможно доказать статически, то правило считается нарушенным.


  3. Не использовать динамическое распределение памяти после инициализации.


  4. Любая функция должна уместиться на одном стандартном листе бумаги, одно выражение на строку и одна строка на определение. Обычно это означает, что функция не должна быть длиннее 60 строк.


  5. Должно быть не более двух ассертов на функцию. Ассерты используются для проверки аномальных условий, которые не могут произойти при реальном запуске. Ассерты не должны содержать сайд-эффектов, и по формату должны быть Boolean-тестами. Когда ассерт падает, должно запуститься специальное действие по восстановлению, например, возврат условия падения обратно в вызывающую функцию. Если проверяющая программа доказывает, что ассерт никогда не фейлится или никогда не удовлетворяется, то правило считается нарушенным. (Нельзя обойти это правило с помощью бессмысленных “assert(true)”).


  6. Объекты с данными должны быть задекларированы на самом низком (из возможных) уровне области видимости.


  7. Возвращаемое значение не-void функции должно проверяться вызывающей функцией. Валидность параметров должна проверяться внутри каждой функции.


  8. Препроцессор можно использовать только для включения header-файлов и простых макро-определений. Token pasting, вариативные функции и рекурсивные макро вызовы запрещены. Использование условных директив компиляции нежелательно, но иногда неизбежно. Это означает, что только в редких случаях уместно использовать больше чем одно или два условия в директивах компиляции, даже в больших проектах.


  9. Использование указателей должно быть ограничено. Допустимо не больше одного уровня разыменования. Операторы разыменования не должны быть скрыты в макро определениях или внутри typedef. Указатели на функции запрещены.


  10. Весь код должен компилироваться при всех включенных warning'ах, на самых дотошных настройках компилятора с самого первого дня разработки. Весь код должен компилироваться с такими настройками без единого warning'а. Весь код должен проверяться каждый день (как минимум раз в день, но желательно чаще), с использованием лучшего из доступных на текущий день статического анализатора кода, и должен проходить анализ без единого warning'а.
Метки:
Hexlet 54,09
Практические уроки по программированию
Поделиться публикацией
Похожие публикации
Комментарии 117
  • –40
    Вот интересно, они(NASA) планируют использовать Rust? Вроде, язык хорошо подходит под их цели, множества ошибок помогает избежать.
    • +4
      Думаю они не изменят свои методы
      • +60
        Вот заняться им больше нечем, кроме как переписывать весь код каждые х лет на новом модном языке.

        Не считая того, что ни один другой язык не имеет такого широкого охвата в плане того что на нём и ядра ОС пишут, и дрова, и программы.
        Си как был 40 лет назад, так и есть до сих пор, а учитывая правила описанные выше думаю у них очень незначительные проблемы с тем чтобы взять древний код и заюзать его.
        • –81
          Rust — не «еще один модный язык». Советую все же ознакомиться с основами языка, либо не демонстрировать свое невежество.
          • +76
            А вам советую подумать о том, что когда мы говорим о проектах, которые занимают десятилетия (от момента запуска до точки назначения зачастую полёты годы занимают), то язык, первый релиз которого вышел чуть больше года назад — это просто несерьёзно. Вот пройдёт лет 10 — можно будет о чём-то говорить.
            • +2
              А на каком языке они по вашему писали в 70е?
              • 0
                Там несколько языков было. Ассемблер, виртуальная машина от MIT и прочее, но, уж конечно, не С. С там появился, скорее всего, в 80е, примерно когда Space Shuttle начали разрабатывать.
                • 0
                  Кого начали? Когда начали?

                  Space Shuttle полетел в 1981 году.
                  • –2
                    То есть шли на риск использовать технологию моложе 10 лет?
                  • 0
                    Что-то железячное могли писать на Ada — с полгода назад на гиктаймсе статья пролетала, что в НАСА скоро останутся без последнего разработчика, способного что-либо сделать с Вояджером (кажется) — ибо док уже нет, спец остался один и тот имеет очень пенсионный возраст…
                    • 0
                      На Ada и сейчас пишут, пишут активно. И железное, и высокоуровневое. В NASA, ESA. Как у нас — не знаю, слишком мало информации у меня.
                • +11
                  Ок, пусть не модный, просто ещё один.

                  Есть огромная вселенная языка Си: куча платформ, компиляторов, библиотек.
                  Ещё куча всякого кода, примеров, проектов и тп.

                  Есть остальные языки, которые часто заимствуют код из мира си, либо портируя либо подключая библиотеки.
                  При этом они сами ничего полезного другим предоставить почти всегда не в силах: оно само не портируется в другие языки, подцепить в качестве библиотеки их как правило сложно/не возможно.

                  Можно приводить сколько угодно любых других кроме Си в пример как более удобные, показывать их фичи, но всегда когда ни них пишешь ты рано или поздно (зависит от размеров проекта и что он делает) упираешься в то, что тебе нужно что то из мира Си.

                  Си не универсальный, многие относительно простые вещи проще и быстрее писать на других языках.

                  Вот они там у себя пишут что на нам можно писать дрова, ядра ОС и прочее.
                  А что вообще на Rust написано?
                  Как собрать RUST прогу под какой нибудь эльбрус? или ущербный контроллер?

                  Тут вот написано где и в каком виде он есть: https://doc.rust-lang.org/book/getting-started.html
                  Венда, мак и фря только х86.
                  И что с этим делать? И главное зачем?

                  Я уже молчу про то, что в нём вообще смысла нет, пока весь остальной код написан Си, та же операционка которую он дёргает.
                  Подход НАСА с упрощением кода и максимальной диагностикой даст результат не хуже раста.
                  • –17
                    Сразу видно что вы ничего не знаете про rust. Он будет работать и на контроллере и на эльбрусе. А уж с интеграцией в си проекты вообще никаких проблем.
                    К тому же никто и не собирается переписывать все что есть, речь про написание нового кода.
                    • +2
                      Языков и раньше было не мало, а сейчас их стало много.
                      Тратить на каждый новый язык время, изучая ради изучения смысла не вижу. А для большинства задач мне хватает Си, иногда перла, иногда пхп, иногда sh скриптов (у меня баша в системе нет).

                      Разумеется, когда нибудь может быть будет работать где то ещё, но сейчас там очень скромный список архитектур.

                      Ответа на простой вопрос: зачем писать на RUST, когда можно написать на… нет.
                      Более того, даже ниша его применения не очень то очевидна.
                      Проектов на нём тоже практически нет.

                      Для академической среды или для не очень практических задач думаю оно вполне, а для серьёзных проектов лучше использовать более проверенные и предсказуемые (в плане развития и понимания что оно не помрёт к концу проекта/через 5 лет) языки.

                      2 ctacka:
                      Это да, но иногда проще взять другой язык и за пять минут натяпляпать там какой то рабочий прототип, в некоторых случаях этого более чем достаточно.
                      В своё время мне надоело писать на Си UPnP сервер (логику), уж сильно много возни было с XML-SOAP и всякими там кодировками XML и я переписал на PHP, а для HTTP взял nginx. Этот проект на PHP мне проще писать/отлаживать, даже при почти полном отсутствии знания и понимания PHP.
                      • 0
                        Не нужно переписывать/отказываться от старого кода, он без проблем подключается и применяется.

                        Ответ на вопрос «зачем?» заключается в наличии гарантий безопасного управления памятью без оверхеда на это в рантайме. Именно это бич Си, именно это могло бы пригодиться в NASA для сверхнадёжных программ.
                        Только не надо говорить, что это не проблема, это уже стоило человечеству очень многие миллионы долларов в ретроспективе.

                        Но, естественно, нет смысла в NASA переключать сейчас разработку на RUST 1.0.сколько-то.alpha, надо дождаться стабильной стандартизированной проверенной версии, полностью на 100% отлаженного и доверенного компилятора и т.д.
                        Рассматривать в перспективе есть смысл, чисто из-за этой фишки с памятью.
                        • 0
                          Хз о каком биче вы говорите, у меня нет проблем с управлением памятью в Си.
                          Я тоже стараюсь по меньше выделять/освобождать во время работы, и по больше использовать либо статические либо выделенное в начале работы.

                          Опять же хз какое у них там железо, я слышал что у нас делают х одинаковых систем, которые считают одно и тоже, и результат большинства считается правильным.
                          Те там помимо программных ошибок бывают ещё аппаратные сюрпризы.

                          Опять же, специалистов наСильников найти проще, и это не меняется уже 2-3 десятка лет, а учитывая что на нём написаны ОС и вообще это почти стандарт де факто (в тех же RFC примеры или псевдокодом или Си) то ситуация не изменится и в будущем.

                          В этом плане американцы пошли проверенным путём: взяли и написали жёсткие стандарты как надо делать, а дальше или у тебя получается нормальный результат или тебя увольняют по не соответствию.

                          И мне вспоминается Visual Basic: на нём тоже было всё быстро и безопасно, и не считая того что он внезаптно почти умер, там всегда была проблема с вызовом WinAPI — нужно было руками писать декларации функций. Отдельно там были «приятные особенности» с выделение буферов, получением указателей и пр.
                          Когда в 2002 году перешёл на Си с ВБ прям почувствовал себя белым человеком, для которого всё уже сделано: и декларации функций и примеры кода…
                          Во всякие огороженные загончики я теперь не хочу, не стоит оно того, не стоит. ИМХО.

                          Никакой язык не гарантирует никаких сверхнадёжностей, его пишут такие же люди. А тем более для RUST нужна ещё операционка, сам то по себе работать не умеет.
                          • 0
                            есть одна мааааленькая проблема:
                            для RUST наверняка нужен процессор с MMU (memory managment unit — блок переназначения виртуальной памяти в физическую).
                            А это и падение быстродействия, и требование наличия ОС, и в разы больше транзисторов и триггеров.
                            А всё это даёт дополнительные точки отказа, особенно в среде с повышенной радиацией, а по «праздникам» с зашкаливающей радиацией. Что есть не самая лучшая идея особенно ради просто моды.

                            Ладно, чёрт с ней с физикой и сложностью.
                            Мне вот интересно другое: есть ли методика безопасного кодинга, проверки и поиска ошибок для RUST выстраданная десятилетиями и миллиардами долларов убытков? Надёжные инструменты которые не дают незначительные ошибки раз в 100000 строк кода? Проверенные годами библиотеки? Надеюсь за фанатов что есть.
                            • 0
                              для RUST наверняка нужен процессор с MMU (memory managment unit — блок переназначения виртуальной памяти в физическую).
                              Нет, Rust'у нафиг не нужен MMU. И вообще он один из редких совеременных языков, способных на голом «железе» сидеть, без операционки, на микроконтроллере с ограниченной памятью.

                              Мне вот интересно другое: есть ли методика безопасного кодинга, проверки и поиска ошибок для RUST выстраданная десятилетиями и миллиардами долларов убытков?
                              Какие могут быть «выстраданные десятитителиями методики», если языку чуть больше года? Позаимствованные из других языков — да, есть, там много идей, «проверенных годами» идей, которые теоретически должны обеспечивать «безопасный кодинг», но как оно там на практике больших проектов в миллионы строк работать будет — ещё рано говорить.

                              Молодой Rust пока — это да, но задатки хорошие. Переводить на него всякие сильно критичные системы — я бы пока не стал. А вот какой-нибудь мелкий проект — уже вполне можно изображать…
                        • 0
                          Первая стабильная версия Rust вышла лишь в том году а вы хотите чтобы на нем писалось ПО для космических кораблей? Ну ну. Может лет так через 10, если язык покажет свою живучесть и станет более или менее стабильным, будет смысл поговорить об этом.
                        • +8
                          Си не универсальный

                          Си как раз универсальный. На нем можно написать что угодно. И практически как угодно.
                          • +4
                            Скорее всего поразумевалось, что Си не очень подходит, когда нужно высокоуровое программирование. Просто не ээфективен за счет более низкой скорости разработки.
                      • +4

                        40 лет назад — это 76-й год. В то время в C был принят такой способ определения параметров у функции:


                        int foo(a, p) 
                            int a; 
                            char *p; 
                        { 
                            return 0; 
                        }

                        Более-менее современный C — это ANSI C 89-го года или ISO C99.

                        • +15
                          И кто мешает взять такой код и скомпилировать его сейчас? На любой платформе любой популярный компилятор его соберёт.
                          • 0
                            надо же собрался — никогда не задумывался об этом. жаль c++ не берет, а было бы удобно с трехэтажными шаблонизированными параметрами, что-то типа auto возвращаемого значения в c++11
                            • –1
                              Бюджет.
                              • 0
                                Нарушите правило 10 :)

                                Любой современный компилятор на такую архаичную запись выдаст предупреждение.
                                • 0
                                  Любой это какой? gcc с ключами -pedantic -pedantic-errors -Wall, например, прекрасно это лопает, даже в принудительном режиме C99.
                                  • 0
                                    И даже в C11. Потому что даже в C11 — это неотъемлемая часть языка C. Только в приложении «Future language directions» упоминается, что эта фича, в общем, довольно давно устарела и, возможно, когда-нибудь, от неё таки и откажутся. Может быть.
                          • +5

                            Я согласен с тем, что Rust хорошо сочетается с заявленными целями писать максимально безопасный код. Но если запретить динамическое выделение памяти, то его преимущества перед C радикально уменьшаются.


                            Don't get me wrong. Я люблю Rust и надеюсь, что он получит большее распространение в обозримом будущем.

                            • +4
                              Но все же, нет особой необходимости менять на Rust.
                              • 0
                                Для NASA может быть и нет. У них, надо полагать, все эти правила не только на бумажке написаны, но и проверяются статическими анализаторами и сотнями тестировщиков. А остальным, всё-таки, стоит задуматься.
                          • +1
                            А чем указатели на функции плохи?
                            • 0
                              Как вы собрались правило #2 будете проверять с указателями на функции?
                              • +1
                                Ну у выбранной функции (стратегии), которая вызывается по указателю, может быть такая проверка.
                                • +1
                                  Это значит что нужно выходит за рамки C и расширять язык. Скорее всего они этим заниматься не хотят.
                                  • 0
                                    к чему эти уложения? чтобы сложнее проверять и легче допустить ошибку? а если марсоход встанет из-за этой ошибке. В их деле не стоит гнаться за скоростью написания кода
                                  • 0
                                    ЛЕГКО. Вызов функции по указателю просто не влияет на циклы.

                                    Как пример использования. Есть функция — запаковать в пакет прикладного уровня и отправить. И у неё аргумент — функция отправки транспортного уровня. Транспортных подсистем — 3-4 штуки. Соответственно делаются обертки к функции запаковки — запаковать и отправить таким-то транспортом (или транспортом, указанным в конфиге).

                                    В итоге получается достаточно безопасная конструкция.

                                    Преимущество — память на прикладной конверт выделяется той функцией, которая знает, сколько памяти надо.

                                    Все это можно сделать через свитч, но оно менее расширяемо получится.
                                  • 0
                                    Не ясно чем их заменить с C. Когда, к примеру, требуется вызов функции по системному таймеру, обычно адрес фукнции записывается в отведенную для вызовов таймера ячейку и при наступлении события таймер дергает функцию, адрес которой там указан. Чем заменить этот механизм?
                                    • +1
                                      Вероятно они предполагают писать статичный код целиком, то есть с известными именами функций и ветвлениями. Для небольших проектов такое могу представить.
                                      • 0
                                        Судя по правилам — они используют какой-то инструмент, перебирающий все доступные варианты ветвления (доказательство корректности программ?).
                                        • 0
                                          Я думаю, это обычный статический анализатор, и судя по тексту — общедоступный, а не какой-то свой.
                                          • 0
                                            Там упоминается MISRA, а не так уж много анализаторов, которые это умеют.
                                      • +1
                                        А зачем этот механизм менять? Я так понимаю что контантные указатели на функции, обусловленные железом, не запрещены. Кроме того я уверен, что у них есть много высокоуровневого кода, который не влияет на выживаемость железяки и для него требования не такие жёсткие…
                                        • +3
                                          Перевод неверный или исходник перевода сам корявый. По той же ссылке на оригинальные правила:

                                          *29 Do not use non-constant function pointers.
                                          30 Do not cast function pointers into other types.

                                          • +1
                                            Кстати, да. И в том же документе как раз много чего про использование указателей на функции, откуда взялся запрет — непонятно. Ну разве что в таком контексте: «IPC messages should then contain only data, preferably no data pointers, and
                                            never any function pointers». Что-то не так тут с переводом, одного беглого взгляда на огигинальный документ достаточно чтобы это понять.
                                        • +6
                                          Вычислимые адреса переходов/вызовов чреваты непредсказуемостью поведения программы так сказать второго рода, когда некорректные входные данные способны не только породить некорректные выходные (GIGO), но и разрушить логику работы конечного автомата — а это может привести к полному краху системы.

                                          В случае же, когда все переходы определены в статике, бортовая вычислительная система представляет собой конечный автомат с памятью, который всегда можно перезапустить очисткой (приведением) набора входных данных к валидному состоянию.

                                          Все вышесказанное, конечно, имеет смысл либо для гарвардских архитектур, либо для систем с защитой памяти (не обязательно имеющих виртуальную!)

                                          Динамическая память — туда же. При отсутствии механизма виртуальной памяти невозможно гарантировать 100% корректную работу системы в течение бесконечного времени при динамическом выделении/освобождении памяти даже при любом априори предустановленном суммарном лимите для каждого процесса из-за фрагментации. При наличии механизма виртуальной памяти такое становится возможным — но взамен мы получаем лишь статистическую верхнюю границу времени отклика на выделение блока памяти
                                          • 0
                                            Невозможно (или слишком сложно) проверить корректность перехода по произвольному адресу, особенно когда данные и код в одном сегменте. При малейшей ошибке последствия очень плохие. Так что переход строго по константам со строгой типизацией. Если нужно разнообразие, то достаточно case.
                                          • +28
                                            Вот где реально интересно было бы посмотреть на результаты прогона PVS-Studio :)
                                            • +4
                                              • +3
                                                Некоторые вещи в статике не протестируешь :)

                                                У Европейского космического агенства была крутая новая ракета Cluster. Там дажу было горячее резервирование системы управления ракетой — но и оно не спасло от необработанного exception. Обе ноды синхронно упали :)

                                                Эта неудача входит в список самых дорогих ошибок программистов
                                                • +8
                                                  Вот где реально интересно было бы посмотреть на результаты прогона PVS-Studio :)


                                                  Кстати да. Призываю в тред Andrey2008
                                                • +13
                                                  «The assertion density of the code should average to a minimum of two assertions per function.»

                                                  В среднем должно быть не менее двух ассершнов на функцию.
                                                  • +5
                                                    Дополню.
                                                    The return value of non-void functions must be checked by each calling function

                                                    Возвращаемое значение не-void фунций должно проверяться вызывающей функцией.

                                                    Примечание: идея такая, что функция не должна доверять ничему вообще, кроме себя самой, ни переданным аргументам, ни значениям полученным из других функций.
                                                    • +4

                                                      А я думаю — как assert(true) может помочь обойти правило не более двух ассертов.
                                                      Так намного больше смысла.

                                                    • –11
                                                      «10 правил, которые позволяют NASA писать миллионы строк кода с минимальными ошибками» —> «10 правил, которые заставляют NASA писать миллионы строк кода».
                                                      • +42
                                                        Крутая сатира. Поддел так поддел. В то время, когда любой программист на php/node может написать код для кьюриосити за два вечера и пару десятков тестовых запусков, nasa тратит десять лет на один-единственный запуск. Вот лузеры же.
                                                        • +2
                                                          Да… Как же плохо что программистов заставляют писать хороший код
                                                        • –4
                                                          Слышал что UI у spacex на HTML пишут. Может это все доказывает, что неважно какой язык, главное какие программисты?
                                                          • +13
                                                            А какая разница, на чем интерфейс отрисовывать?
                                                            • +24
                                                              Ну летите вы к земле, а на лендинг странице кнопочка приземления уехала.
                                                              • +1
                                                                насколько я понимаю, все важные кнопочки приземления выполнены в виде хардварных тумблеров. а интерфейс на хтмл — для разного рода научных программ и прочих тестов в невесомости.
                                                                • +1
                                                                  скорее продублированы. Потому что экран может сломаться
                                                          • +1
                                                            Собственно, все самое интересное находится в документах MISRA C с примерами как делать хорошо и как плохо
                                                            • +11

                                                              Великолепные правила для неспешной разработки надёжных систем. Ужасные правила для быстрой разработки ненадёжных систем.


                                                              image

                                                              • +15
                                                                0. Иметь бюджет $1,000 на одну строку кода.
                                                                • +3
                                                                  зато какая приятная работа для души, прямо строительство идеального механизма.
                                                                • 0
                                                                  У всех циклов должен быть предел. Проверяющая программа должна иметь возможность легко доказать, что определенное количество итераций не может быть превышено. Если предел невозможно доказать статически, то правило считается нарушенным.


                                                                  Хотелось бы узнать больше подробностей, ибо известно, что в общем случае проблема останова не решаема.
                                                                  • +2
                                                                    В общем случае рассматривается общая программа. Ваш КО.

                                                                    Какой-нибудь BPF в проблему останова ни разу не упирается, почему NASA должна?
                                                                    • 0
                                                                      Какой-нибудь BPF в проблему останова ни разу не упирается, почему NASA должна?


                                                                      Странная логика. Я не говорил, что "NASA должна".
                                                                      В документе JPL есть много правил, но пользователь Реддита сделал выжимку десяти главных принципов.


                                                                      то есть скорее всего есть какое-то формальное доказательство, что следуя всех их правилам, можно гарантировать, что программа завершиться за конечное число шагов. Я лишь хотел подчеркнуть, что вне контекста правило №2 непонятно совсем. Более того, непонятно, как его выполнять.
                                                                      • +1
                                                                        Правило совершенно понятно вне контекста, и, на мой взгляд абсолютно ясно, как его выполнять: не надо писать циклов неопределённой продолжительности. Наверняка, в других документах вдобавок прямо сказано, что любая процедура в прошивке космического корабля обязана гарантированно возвращать управление, скажем, не более чем через 100 мс.

                                                                        На практике это означает, что сложные алгоритмы должны быть ограничены не только достижением результата, но и заданным количеством итераций до неуспеха.
                                                                    • +2
                                                                      Так они не программируют общий случай алгоритмов. Задача, вычислительная сложность которой неизвестна, не должна программироваться в бортовой компьютер.
                                                                      • +2
                                                                        Математическая поправка: машину Тьюринга нельзя построить, так как она сама по себе бесконечная (это требуется для доказательства некоторых теорем). Для алгоритма, выполняемого на конечной системе, всегда можно решить проблему остановки, так как она является тривиальной для такой системы. В этом случае машина Тьюринга будет эквивалентна некоторому большому конечному автомату (что, кстати, косвенно обсуждается в предложенных правилах от JPL), для которых существуют хорошие алгоритмы проверки формальной корректности.

                                                                        Вот пример

                                                                        http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20030017985.pdf

                                                                        Да и вот тут много чего интересного есть

                                                                        http://lars-lab.jpl.nasa.gov/
                                                                        • 0
                                                                          абсолютно верно, конечные автоматы и ватч доги в каждой точке где возможно зацикливание резко сокращают неопределенность системы
                                                                        • –1
                                                                          Просто ребята умно перефразировали «никогда не пишите while(true)» :)
                                                                        • +5

                                                                          Что-то я сомневаюсь, что дело в 10 правилах.


                                                                          Дело скорее:
                                                                          В детальном прописывании спецификаций и их низменности на протяжении всего времени разработки
                                                                          В статическом анализе кода
                                                                          В обязательном code review
                                                                          В огромных затратах на тестирование


                                                                          В таких условиях неважно на каком языке ты пишешь и какого стиля придерживается.


                                                                          Очевидно, что правила про отсутствие динамической памяти, рекурсии, ограниченность циклов и отсутствие указателей на функции появились чтобы упростить работу статическому анализатору

                                                                          • +3
                                                                            Да нет там запрета указателей на функции. И вообще, как умудрились при переводе 31 правило (а то и 33) упаковать в 10, да ещё и переврать — непонятно.
                                                                            • 0
                                                                              Не-не-не, это как правила дорожного движения. Если их не соблюдать, то никакие навигаторы и техосмотры не помогут.

                                                                              Анализатору и компилятору пофиг, он машина. Запятые, скобки на месте? Годен! А вот живому человеку сложно читать и отлаживать код, в котором много условностей и контекстов. Забудешь вернуть память или выйти из рекурсии — и привет. Проще это болото обойти, потратишь лишний час разработки, но сэкономишь недели и месяцы отладки.
                                                                              • 0

                                                                                На моей практике наблюдалось явление: чем больше код проверяется, тем внимательнее пишут программисты. Это касается именно проверки исходников, а не тестирования.


                                                                                Добавляя статические проверки и code review к процессу можно сразу получить на порядок лучшее качество.
                                                                                Видимо срабатывает логика: код будут проверять — надо писать хорошо. И обратная логика тоже работает прекрасно. Если никто по факту не код не проверяет, то пишут его абы-как.

                                                                                • 0
                                                                                  Тут дело не в качестве, а в сознательном отказе от использования вполне корректных и полезных, но потенциально опасных возможностей.
                                                                                  • 0

                                                                                    Еще раз повторю тезис.


                                                                                    Дело вовсе не в отказе, в большем контроле что пишут программисты.
                                                                                    Сколько бы ограничений вы не вводили — это не поможет не писать говнокод, если программист захочет.


                                                                                    А если заранее спланировать что напишет программист, проверить статическим анализатором, прогнать через code review минимум двух человек и потратить в два раза больше времени на тестирование, то по сути пофиг какие там ограничения вы себе навводили.

                                                                                    • +2
                                                                                      Говнокод писать можно и нужно. Потому что у кода, от которого зависит сохранность имущества и жизни людей нет оценки говно-охуенно. Он либо работает как надо в любой ситуации, либо не работает и происходят плохие вещи. А как оно там внутри, грамотно или говняно — никого совершенно не интересует.

                                                                                      Вот, к примеру, 5-й пункт про ассерты. Они никак не влияют на функционал, это тесты. Они жрут такты при каждом вызове функции, особенно в циклах. Но это самые точные тесты, которые легко поддерживать актуальными. А еще они, в отличии от юнит-тестов, способны сохранить программу «на плаву» уже в полете, когда невозможное случилось и без отладчика точно указать на проблемное место.

                                                                                      или 7-й пункт, проверять все, что пришло снаружи или изнутри, будь то параметры или результаты. Например, банальная функция инкремента. Знаете, что будет с байтом 0xFF, если его увеличить на единицу? Будет ноль. А это во некоторых случаях может привести к беде. Поэтому в самом инкременте должен быть ассерт на переполнение, и на выходе нужно проверить, что результат инкремента является допустимым. Глупости? Отнюдь! Реальный пример — при формировании более светлого цвета фона для выделения важного сообщения происходило переполнение байтов RGB и получался черный текст на черном фоне. 15 лет работало нормально, а потом в системе поменяли цвет фона на чисто белый (0xFFFFFF) и получился эпический фейл. Вот каким анализатором или code review можно было такое предусмотреть?

                                                                                      С указателями самая больная тема. Нетипизированные указатели это граната с обезьяной. Проще сразу отказаться, чем потом страдать. Память из кучи это по сути своп — там и фрагментация свободного места, и конфликты, и утечки. Когда используется всего 5-10% от свободного объема, то это незаметно. А когда памяти впритык, то начинает всякая фигня происходить. Может всплыть через месяц, через год. Поэтому тестирование таких вещей идет неделями с 10-кратной нагрузкой на пределе возможностей железа.
                                                                              • 0
                                                                                Низменность детально прописанных спецификаций — сильно!

                                                                                Высокодуховный код безбажен по определению :)
                                                                                • +2
                                                                                  Вспомнилась интересная (даже спустя 20 лет после написания) статья о том, как устроена работа в одной из групп, разрабатывающей ПО для бортовых систем шаттлов: They Write The Right Stuff. В числе прочего, в ней есть интересные данные по доле ошибок в расчете на количество строк кода, по объему и качеству спецификаций в проекте, а также по размеру его бюджета. Пара цитат, передающих общую идею:

                                                                                  «Our requirements are almost pseudo-code,» says William R. Pruett, who manages the software project for NASA. «They say, you must do exactly this, do it exactly this way, given this condition and this circumstance.»

                                                                                  The group has one customer, a smart one. And money is not the critical constraint.

                                                                                  Ничуть не принижая способности их разработчиков, следует отметить, что с организационной точки зрения условия им созданы очень близкие к идеальным.
                                                                                  • +1
                                                                                    У меня тоже задачи однозначны, просты и понятны, любой студент справится. Вся проблема в том, что в системе должно быть 0 (ноль) ошибок на 560 000 строк кода. И работать она должна несмотря ни на какие сбои и неполадки железа и софта, ошибки персонала. Но, в отличие от НАСА, денег и ресурсов минимум, а ответственность не меньше.

                                                                                    Скрытый текст
                                                                                    Пульт центрального наблюдения для ohrana.gov.by Немного почитать — www.serbod.com/projects-taken/rf-link

                                                                                    • 0
                                                                                      в системе должно быть 0 (ноль) ошибок на 560 000 строк кода. И работать она должна несмотря ни на какие сбои и неполадки железа и софта, ошибки персонала.

                                                                                      Стандартное в наши дни требование практически от любого заказчика в корпоративном сегменте :)

                                                                                      А если серьезно, то некоторые из описанных задач, конечно, далеко не для любого студента. Поделитесь, какими способами пытаетесь поддерживать низкое количество ошибок в системе, в которой есть сторонние компоненты, включая целые базы данных, а также
                                                                                      некоторые драйвера устаревших приборов невозможно протестировать и отладить, потому что они сложные, к ним нет ни документации, ни тестовых приборов

                                                                                      ? Используете похожие на NASA'вские правила при разработке? Требуете как и они от заказчика подробнейшие спецификации? Содержите ли сильнейший отдел тестировщиков? Пытаетесь вытягивать на личных профессиональных качествах старших разработчиков?
                                                                                      • 0
                                                                                        Ошибки в коде для системы вовсе не повод, чтобы не работать. =) Система разбита на множество компонентов, и если ломается один, то остальные либо ждут его восстановления, либо переключаются на запасной. Главное, чтобы поставленные задачи решались в пределах допустимых отклонений от нормы. И не допускать повторения ошибок.

                                                                                        Лично я правила использую. Но не всегда им строго следую. Требовать спецификации можно, но не всегда успешно. И в них могут быть ошибки, устаревшие сведения. Только практика, испытания и анализ дают достоверный результат. Тестировщики есть, и очень дотошные. Личные качества вообще самое главное, ведь технику делают люди.
                                                                                        • 0
                                                                                          Требовать спецификации можно, но не всегда успешно. И в них могут быть ошибки, устаревшие сведения.


                                                                                          "В 1962 году головной по командному модулю кораблей серии «Аполлон» фирмой «North American Aviation» (позже — «North American Rockwell») при изменении технического задания на изготовление кислородных баллонов для двигательных отсеков, выданного субподрядчику фирме «Beech Aircraft», не была предусмотрена модификация термостатов, изначально рассчитанных на напряжение 28 В, под стандартное для наземного оборудования стартового комплекса напряжение в 65 В. Это несоответствие не было замечено ни специалистами обеих фирм, ни НАСА. [...] проведённые в ходе расследования эксперименты показали, что эти выключатели, рассчитаные на питание в 28 вольт постоянного тока от батарей служебного модуля, не размыкались должным образом при работе под напряжением 65 В, подаваемым со стартового комплекса в ходе выпаривания кислорода."
                                                                                • 0
                                                                                  В NASA JPL большие молодцы. Но поучительно помнить, что все эти правила не помешали едва не угробить марсоходы… из-за банальной вещи — из-за того, что на Земле никто не протестировал случай, когда марсоход наделал много фотографий и его FLASH-память почти заполнилась.
                                                                                  • 0
                                                                                    Память закончилась не из за фотографий, а из за ошибки реализации файловой системы, которая приводила к неполному освобождению места при удалении файлов/папок.
                                                                                  • 0
                                                                                    Читал ровно эти самые десять правил лет 7 назад в каком-то англоязычном журнале, написано было один в один
                                                                                    • 0
                                                                                      Правило #7, кажется, называется defensive programming и считается немного противоречивым.
                                                                                      • 0
                                                                                        Для NASA — в самый раз. Подобный подход приводит к тому, что ошибки имееют меньше шансов привести к провалу миссии, но увеличивают вероятность того, что останется ошибка, которую сможет использовать «враг». Так как бортовому компьютеру с атаками на безопасность сталкиваться не приходится — то выбор очевиден.
                                                                                      • +3
                                                                                        > Объекты с данными должны быть задекларированы на самом низком (из возможных) уровне области видимости.

                                                                                        А самая низкая, это где? Самая глобальная или самая локальная?
                                                                                        • +1
                                                                                          Самая локальная. Ну это более или менее здравый смысл — если переменная нужна только в конкретном блоке кода, делать ее глобальной это заранее создавать себе крупные проблемы.
                                                                                        • +4
                                                                                          Эти правила просто напросто вытекают из ограничений той самой «проверяющей программы», которая вскользь упоминается в некоторых из них. Само собой, что если у тебя такая программа есть, то ты вынужден писать код таким образом, чтобы она могла его проверять. Но использовать эти правила, не имея в своём распоряжении проверяющей программы, — это то же самое, что и не иметь автомобиля, но при этом передвигаться в сидячей позе, выставив вперёд руки, которые, как бы, держат руль, и издавая ртом звуки, имитирующие работу двигателя.
                                                                                          • +2
                                                                                            Нет, к этим правилам рано или поздно приходит любой разработчик масштабной системы с высокими требованиями.

                                                                                            Когда я впервые столкнулся с этим при разработке под игровые приставки (на картриджах), то тоже был несколько скептичен. Зачем же себя так ограничивать? Но позже, при отладке совершенно непонятных рандомных глюков, постепенно пришлось отбрасывать весь синтаксический сахар, регламентировать работу с памятью и вставлять сотни ассертов. В итоге ошибка находилась, они могла быть совсем пустяковой, и не влиять на работу сразу, а вызывать сбой где-то в другом месте программы.

                                                                                            Я бы еще добавил, что очень важна строгая типизация и однозначно говорящие имена функций и переменных. Сколько угодно случаев, когда тупиковая ситуация переставала быть тупиковой, когда вещи называли своими именами.
                                                                                            • –1
                                                                                              Случаем, не так сделали?
                                                                                              #define TRUE 1
                                                                                              #define FALSE 0
                                                                                              typedef int BOOL;
                                                                                              
                                                                                              // где-то в коде
                                                                                              BOOL a;
                                                                                              // повсеместно заместо
                                                                                              // a = TRUE;
                                                                                              a += 1;
                                                                                              
                                                                                              • 0
                                                                                                У вас BOOL это синоним целого числа. В принципе, иногда допустимо, но тогда это iBool_t

                                                                                                enum Boolean { FALSE = 0, TRUE = 1 }; // ибо нефиг!
                                                                                              • +1
                                                                                                И объясняется это почти тем же самым. При разработке масштабных систем обычно происходит ревью кода другими разработчиками. Это бюджетный аналог той самой «проверяющей программы», использующий ручной труд вместо автоматизации. И, естественно, у этих разработчиков тоже есть свои ограничения. Некоторые из них плохо понимают хитроумные макросы. Поэтому их нельзя использовать. Некоторые другие вообще не знают всей кодовой базы в целом, и поэтому им не нравится код с исключениями, так как они сходу не могут понять, где и как исключение будет обработано. Им хочется смотреть в код только там, где были сделаны изменения, и чтобы сразу всё было понятно. Третьи разработчики плохо понимают С++-шаблоны, и поэтому их разрешено использовать только самым простым и очевидным способом. Так постепенно шаг за шагом формируются все эти правила. И, наверное, это правильно. Я собственно не возражаю. Единственное, меня смущает то, что этим правилам обычно приписывается некая универсальность. Якобы они имеют смысл не только в какой-то конкретной команде разработчиков, а вообще все должны их придерживаться. Типа, так код становится «более читаемым». Хочется спросить: «Читаемым кем?» А если код, например, ревьювят Александреску и разработчики boost? Почему бы не использовать шаблоны более агрессивно? Или если код ревьювит хардкорный сишник с 30-летним стажем? Почему бы не использовать сложные замороченные макросы? Ему будет приятно видеть, что кто-то ещё знает толк в извращениях. В общем, суть в том, что правила написания кода следуют непосредственно из ограничений проверяющей системы. Не важно, ручная она или автоматическая. Эти ограничения следует чётко осознавать, и тогда правила не будут выглядеть нелепо.
                                                                                                • +3
                                                                                                  Разработчики становятся «некоторыми другими» даже после больничного или отпуска. А еще есть задачи, где абсолютный приоритет простоты и надежности над красотой и крутостью. Когда функция из десятка строк, (где 7 строк это проверки и обертки) лучше одной inline строки или макроса. Наважно, что в эту функцию попадет — корректное значение, некорректное или бозон Хиггса — она корректно отработает.
                                                                                                  • +1
                                                                                                    Простота и надёжность не противопоставлены красоте и крутости.
                                                                                                    • 0
                                                                                                      Это противоречие между ученым и инженером. Первый — несравним со вторым по красоте решений и крутости, но — немасштабируем (вернее, негарантированно воспроизводим в любой внешней среде, создаваемой государством).
                                                                                                      Вторые — гарантированно воспроизводимы на уровне, скажем, не ниже четверки по профильному предмету при применении обучающего курса Х в течение Y лет.
                                                                                                      Как и любая индустрия, космическая промышленность нуждается в определенном количестве специалистов, способных решать задачи определенного класса с качеством не ниже определенного. Дальше — теория вероятности — чем выше требования к качеству — тем меньшее количество людей статистически годны для решения задач — а значит, а) процесс становится более персонозависимым, и б) прогноз выхода специалистов нужного уровня — недостоверным
                                                                                                      Это допустимо (и усиленно используется!) в гуманитарной области (поэты, художники итд) — но совершенно недопустимо в инженерии. Поэтому вводятся искусственные ограничения, повышающие надежность за счет снижения разрешенного множества выразительных средств — этими мерами процесс выводится из зоны персонозависимости. Снижение эффективности кода и/или красоты решения в данном случае не играют никакой роли (так как либо легко парируются техническими средствами, либо не являются метрикой качества/престижа разработчика вообще)

                                                                                                      Уместна аналогия с переходом от аналогового к цифровому аудио — да, аналоговая запись единственна и неповторима — но она и немасштабируема! Сознательное же внесение искажений в идеал (квантование) позволяет сделать предсказуемой любую ее копию.

                                                                                                      • 0
                                                                                                        Параллель, проведённая между инженерами и художниками, несколько смазывается тем, что художники и поэты в гораздо большей степени, чем инженеры, ограничивают сами себя в допустимых выразительных средствах. Причём делают они это специально для того, чтобы показать свою крутость. У художников это выглядит как кубизм и супрематизм. А поэтов ограничивает необходимость соблюдать ритм и подбирать рифму. У Дэна Симмонса в Гиперионе был забавный персонаж — величайший поэт в галактике. После травмы головы у него что-то поломалось в мозгу и он мог использовать в своей речи только девять матерных слов. Много лет он был вынужден общаться, используя столь ограниченный набор слов. Но зато когда проблема исчезла и появилась возможность использовать любые слова, он с легкостью стал поэтом настолько крутым, что ему не было равных во всей галактике.
                                                                                            • +1
                                                                                              По репозиториям NASA видно, что далеко не только C/C++ используется — Phyton, Ruby, JavaScript, Java, FORTRAN и даже плагин на VB.NET к Excel.
                                                                                              • +1
                                                                                                Это всё не в боротовом компьютере.
                                                                                                • 0
                                                                                                  VB.NET Excel в бортовом компьютере было бы очень забавно. =)
                                                                                              • 0
                                                                                                Интересно, а почему они более серьезные метрики кроме количества строк и ветвлений не вынесли в правила? Статический анализатор включили в правила, а метрики — нет.
                                                                                                • –4
                                                                                                  Правило 0. Не использовать javascript никогда вообще никогда.
                                                                                                  • 0
                                                                                                    > Возвращаемое значение не-void функции должно проверяться вызываемой функцией.

                                                                                                    вызывающей функцией

                                                                                                    Rule 14 (checking return values)
                                                                                                    The return value of non-void functions shall be checked or used by each
                                                                                                    calling function, or explicitly cast to (void) if irrelevant.
                                                                                                    • +1
                                                                                                      В черновиках была правильная версия, в чистовик попала неправильная :-( Спасибо, исправил.
                                                                                                    • +4
                                                                                                      Эти десять правил не «пользователь Реддита» выжал из JPL. Их сформулировал Gerard Holzmann с коллективом в документе «The Power of 10: Rules for Developing Safety-Critical Code» в 2006 году, как раз для JPL. Они вошли в основу нынешнего стандарта, наряду с MISRA C и другими дополнениями.

                                                                                                      Копия статьи: web.eecs.umich.edu/~imarkov/10rules.pdf
                                                                                                      Статья в Википедии: en.wikipedia.org/wiki/The_Power_of_10:_Rules_for_Developing_Safety-Critical_Code
                                                                                                      • 0
                                                                                                        Большое спасибо, исправил пост и добавил вашу поправку.
                                                                                                      • 0
                                                                                                        Бумага, толщина: 500 листов — примерно 50 мм, 1 лист — 0,1 мм. Пусть высота 1,7 м = 1700 мм. 1700/0,1 = 17000 листов. И когда она успела столько набрать?
                                                                                                        • 0
                                                                                                          Миллион строк – в самый раз за несколько лет. Особенно если на ассемблере.
                                                                                                        • 0
                                                                                                          Там в документе всего 31 правило, кстати. Можно было бы их все перевести, остальные там тоже все make sense, десять представленные ничем особым не выделяются от общего списка. И я бы не стал называть их «жесткими». Правила, как правила. В одной организации одни, в других другие. Главное, хорошо, что они есть в принципе, и еще лучше, если им следуют.

                                                                                                          Я думаю, что это все-таки не какие-то определенные правила «позволяют NASA писать миллионы строк кода с минимальными ошибками», а ответственность людей, которые там работают. Наличие правил и их теоретическая осмысленность не гарантируют того, что им будут следовать или применять так, как предполагалось. Скорее все-таки, это в NASA это общее понимание потенциальных последствий даже, казалось бы, маленьких ошибок, заставляет людей намного более ответственно относиться к тому, что они производят, чем в большинстве ПО общего потребления, где факапы не столько значимы.
                                                                                                          • 0
                                                                                                            не могли бы вы дать пруф на «миллионы строк кода»? В оригинале есть только упоминание про «hundreds of thousands of lines», что как бы на порядок меньше:)
                                                                                                            • 0
                                                                                                              Ошибки, ошибки никогда не меняются… Стряхнём пыль с глобуса: проверяем проект NASA World Wind. Copy-Paste он везде. :)

                                                                                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                                                                                              Самое читаемое