Встречаются два программиста — один пишет на Си, другой на Ада. Си-программист говорит: — Я буду бифштекс с луком
Анекдот понятный только для тех программистов, кто в теме )
Разработка программного обеспечения для промышленных систем становится более профессиональной. На рынке становится все меньше поделок под MS Windows, широко используются клиент — серверные решения. Unix — подобные операционные системы, такие как Linux, уже ни у кого не вызывают снисходительной усмешки. Военные заказчики также смирились с тем, что никаких бюджетов (в первую очередь американских) не хватит для собственной разработки базовых программных технологий, и скрепя сердце согласились с тем, что их придется брать с открытого коммерческого рынка — все то, что обозначается краткой абревиатурой COTS.
Модель разработки Open Source доказала свою жизнеспособность, и корпоративные программисты сейчас ломают головы, как использовать лакомые куски уже наработанного открытого кода и не нарушить условия лицензии GPL в своих разработках. Появился выбор инструментов и сред разработки, также появилось большое количество новых языков программирования. До этого в отечественной истории, в частности в разработке средств управления воздушным движением, принимали любые разработки — и на этом спасибо.
Новые времена — от победы любой ценой к надежности
Сейчас другие времена: рынок начинает насыщаться, и заказчики и программисты начинают задумываться о надежности и отказоустойчивости. Теперь нам интересно знать, что у нас с надежностью программного обеспечения в области автоматизированных систем управления воздушным движением? Думается, не нужно объяснять, как это важно для тех, кто находится на борту самолета, который сопровождает диспетчер. А сопровождение возможно лишь постольку, поскольку диспетчер видит всю воздушную обстановку, которую ему предоставляет софт КСА УВД.
Если мы хотим понять, насколько надежным является программное обеспечение КСА, возьмем для примера самую современную отечественную систему — КСА УВД Галактика. На сайте поставщика есть очень хорошие и важные разделы про подтвержденный уровень качества и безопасности, а также про надежность. Но там не хватает одной принципиальной строчки, которая есть у всех зарубежных разработчиков систем Air Traffic Control (ATC). И эта строчка даже не вишенка на торте, которая венчает серьезную и отказоустойчивую систему. Скорее всего, это весь торт и есть.
Но прежде чем мы возьмем лопаточку и начнем препарировать этот тортик, вернемся на много лет назад и попытаемся вспомнить, что мы знаем про язык программирования Ада.
ADA Language: восстание зомби
Вот и я вспоминаю, какие ассоциации вызвало у меня прочитанное про язык Ада. Вначале американскими военными (Departament of Defense — DOD) был разработан стандарт языка. Затем, уже на основе стандарта начали создаваться компиляторы и другие инструментальные средства. Для такого подхода есть даже специальный термин — опережающая стандартизация. И все это где-то затерялось в засекреченных недрах американских военных разработок. Вот такие первые ощущения; а первые — они самые сильные.
После этого я копнул чуть глубже. Фишка языка — встраиваемые системы и большие программные комплексы. Хорошо реализована многозадачность, и это уже интересно. И самое главное преимущество с точки зрения надежности работы программы — строгая типизация языка, которая не дает программисту делать ошибки, которые не обнаруживаются на начальной стадии компиляции и сборки проекта.
Ну хорошо. Мало ли какие прекрасные вещи можно заложить в стандарт, который останется пылиться на полке? Я помню модель протоколов и стандартов OSI, по которым планировалось строить сети во всем мире. Кто сейчас знает про стандарты ISO 8473 CLNP, ISO 9542 ES-IS, ISO 10589 IS-IS и ISO 10747 IDRP, которым предсказывали успешное будущее? Все они отправились в небытие когда появился TCP/IP, и этому протоколу никакие стандарты не предшествовали. Или может вы пользуетесь электронной почтой в соответствии со стандартом X.400, который был специально разработан для нее? Нет, повсеместно работает протокол SMTP, а про X.400 уже никто не вспоминает.
Мировое комьюнити программистов настороженно относится к руководящим документам, которые разрабатывают кабинетные академики, и на тот момент у меня сложилось впечатление, что язык Ада окончательно похоронили вместе с его стандартом. Чтобы в этом удостовериться, надо было копнуть еще немножечко и попробовать отыскать этот язык в виртуальных музеях безуспешных начинаний. Но, на мое удивление, в музее Ады не оказалось.
Зато я нашел этот язык там где уж точно не ожидал его обнаружить: в таких компаниях как Airbas, Boeing, Lockheed — Martin, Thales, Indra (вот эта последняя парочка работающая в ATC особенно интересна), а также в разнообразных критичных системах — начиная от парижских поездов метро, которые едут без машиниста, истребителях и заканчивая станциями, летящими к Марсу, а также ракетами Ariane, Atlas и Delta.
И вот тут стало по настоящему интересно. Где-то в самой что ни на есть профессиональной области элитного уровня существует затерянный мир языка Ада, о котором основная масса программистов, штурмующих PHP и Java в хорошо оплачиваемых web проектах ничего и не подозревает. Каким образом Ада ухитрилась вернуться из забвения и незаметно обосноваться в современности?
Задержка в развитии
Американские военные, породившие язык, все сделали как положено по уставу, то есть стандарту. Но на большее их не хватило: дальше пошли сплошные косяки. Во первых, они решили что весь софт для военных приложений будет крутиться на Аде, что оказалось совсем не так, но дело было сделано: от военных проектов было отброшено большое количество профессионалов, которые нашли себя в области свободных разработок, не завязанных на DOD.
Во вторых, барьер вхождения в эту область повысили еще раз, когда решили сделать лицензии на компилятор и другой инструментарий платными. Эти затраты уже точно стали неподъемными для обычных разработчиков, но вполне по силам крупным корпорациям, которые работают с военными. Для программистов на Ада стало гораздо меньше работы, чем для Си-программистов; и сейчас пожалуй самое время раскрыть смысл анекдота который вынесен в эпиграф. В этом анекдоте Ада программист заканчивает карьеру официантом, которому состоятельный Си-шник заказывает обед )
Эта бесхитростная логика потерпела сокрушительное поражение, когда выяснилось, что со временем круг людей которые разбираются в Ада исчезающе мал, зато те программисты которые получали возможность бесплатного профессионального роста на языке Си в области GNU/Linux, выросли и стали подавляющим большинством. Отсутствие людских ресурсов в Ада программировании привело к тому, что разработчики ПО для нового истребителя F-35 решили отказаться от Ада (на котором разрабатывался софт для F-22 и других самолетов) и начали разрабатывать его на языках C/C++. В результате проект начинает показывать все признаки провального — сложный комплекс ПО никак не удается отладить и запустить в полном объеме.
Со временем, наконец, до всех дошло, что нужно использовать бесплатные и открытые модели разработки, как это давно было сделано в Open Source, и появился свободно распространяемый проект GNAT, ничем по функционалу не отличающийся от лицензируемых инструментов Ада и который может использовать любой программист.
По опубликованным данным, в настоящий момент написано около 50 млн. строк исходного кода на Ада для систем вооружений, и большой объем ПО находится в текущей разработке. В 1996 году в США был произведен анализ рынка ресурсов разработчиков для Ада и Си. Всего было определено 1млн. 920 тысяч программистов, из которых 90.000, или менее 5%, писали на Аде.
ADA vs C
Теперь когда мы закончили с историей, перейдем к сравнительным цифрам, сопоставляя возможности Ада и наиболее популярного языка Си. Это сопоставление ни в коем случае не говорит о том, какой язык хороший или плохой. Они просто предназначены совершенно для разных применений.
Язык Ада можно сравнить с автомобилем, в котором приняты все меры безопасности: подушки, укрепляющие профили в дверях, автоматическая система стабилизации. В таком автомобиле вы будете защищены от неожиданностей, в нем можно возить всю семью и детей не опасаясь за последствия.
Язык Си — это натурально мотоцикл. Он дает вам кучу возможностей по сравнению с автомобилем. Вы можете проскакивать между рядами, газовать с места на высокой скорости и даже ездить по лестницам и заборам. Но это все вы делаете на свой страх и риск, и мотоцикл вам ничего не гарантирует: если что, даже шлем вам не поможет. Вы повезете своего ребенка на мотоцикле?
Кстати насчет шлема: среди менеджеров бытует мнение (к которому программисты, которые «в теме», относятся с большим скепсисом), что путем повышения «дисциплины программирования» и «качественного тестирования» можно убрать все ошибки из кода Си. Это жалкая попытка надеть шлем и при этом говорить, что мотоцикл теперь стал совершенно безопасным. Одной из отличительных особенностей Ады как раз является то, что это язык со строгой типизацией данных, что делает невозможными кучу ошибок, которые легко сделать на Си. И пусть вас не вводит в заблуждение, что программный комплекс работает целый год без сбоев: достаточно редкого сочетания данных и внешних условий, чтобы попасть на нетестированную ветку алгоритма (а все ветви протестировать невозможно), и вот тут дремлющая ошибка может сработать.
Но мы отвлеклись: возвращаемся к цифрам.
Вначале дадим информацию из Вики: по сравнению с Си программами, программы написанные на Ада содержат на 70% меньше исправлений и на 90% меньше багов. Большие преимущества Ада начинают проявляться при сопровождении сложных программных комплексов (а вы думали что самое главное это разработать софт? а вот и нет), где сопровождение «часто составляет около 80% от общей стоимости разработки».
Положим, Википедия не очень сильный авторитет. Обратимся к более весомым исследованиям, и поскольку мы плавно подбираемся к КСА УВД, таким авторитетом для нас будет FAA — Federal Aviation Administration, то есть американский аналог Росавиации, и известная компания IBM. В этой таблице приведены параметры надежного и безопасного программирования по данным FAA и IBM:
Наименование параметра |
Ada 83 | C |
Availabilityм/ Reliability
Доступность / Надежность |
21.5 | 11.6 |
Maintainability / Extensibility
Удобство сопровождения / Расширяемость |
14.0 | 10.2 |
Приведем результаты еще одного любопытного исследования, в котором анализировались параметры проекта, в котором разработка начиналась на Си, затем также начал использоваться язык Ада, который на момент анализа составлял примерно половину проекта:
Наименование параметра |
Ada 83 | C |
Количество строк исходного кода SLOC | 1272771 | 1508695 |
Новые функции | 23031 | 26483 |
Правки кода | 5841 | 13890 |
Правки / новые функции | 0.25 | 0.52 |
Правки / KSLOC | 4.59 | 9.21 |
Стоимость разработки | $8.446.812 | $15.873.508 |
Стоимость разработки / SLOC | $6.62 | $10.52 |
Количество ошибок | 122 | 1020 |
Количество ошибок / KSLOC | 0.096 | 0.676 |
В таблице пересчитаны также относительные значения, приведенные к количеству строк исходного кода SCLOC. Мне представляется, что цифры говорят сами за себя: в проектах написанных на Ада меньше ошибок и они имеют более низкую стоимость разработки. Теперь, когда мы оценили потенциал этого языка, а также обнаружили, что он жив и очень хорошо используется в критичных системах, возникает вопрос: а что с этим в отечественной практике? Из чего состоит КСА УВД Галактика, которую мы выбрали в качестве примера?
КСА УВД Галактика: скучно и предсказуемо C++
Как я упомянул выше, признанные мэтры в области разработки средств управления воздушным движением — УВД (Air Traffic Control — ATC) Thales и Indra используют язык Ада. Теперь это уже далеко не секрет. Также не секрет и то, что все программное обеспечение КСА УВД Галактика написано на С++. Это обстоятельство нигде не афишируется, хотя зарубежные поставщики ATC свободно указывают тип используемого языка в своих материалах.
Как Си, так и его расширение C++ — замечательные языки. Однако они совершенно не подходят для разработки больших критичных систем, где возможно возникновение трудно обнаруживаемых ошибок.
Перейдем к конкретным примерам.
На примере ниже в результате механической ошибки программа Си будет работать совсем по другому алгоритму — не так как вы ожидали. Здесь показан участок кода, который обрабатывает и затем отображает трек воздушного судна и будет выполняться или нет в зависимости от переменной clear:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// корректный Си код if (the_signal == clear) { process_track (var1); show_track (var2); } // механическая ошибка: вместо сравнения "==" указано присваивание "=" // тем не менее, это правильный с точки зрения компилятора код, // и он будет выполнен, но с непредсказуемым результатом if (the_signal = clear) { process_track (var1); show_track (var2); } |
1 2 3 4 5 6 7 8 9 10 11 12 |
-- корректный Ада код if The_Signal = Clear then Process_Track (Var1); Show_Track (Var2); end if; -- если даже сильно постараться и перепутать "=" с ":=" if The_Signal := Clear then Process_Track (Var1); Show_Track (Var2); end if; -- компилятор покажет ошибку и не скомпилирует код! |
В последнем случае компилятор Ада еще и ткнет вас носом, что вы именно перепутали:
1 2 3 |
$ gnatmake uvd.adb gcc-4.6 -c uvd.adb uvd.adb:27:15: "=" should be ":=" |
Си и не подумает вас ни о чем предупреждать. Не забывайте — это мотоцикл, он не ограничивает вас ни в чем, в том числе в таких милых погрешностях, в результате которых диспетчер не увидит метку на экране или увидит ее совсем в другом месте.
Я сам попадал на этот вариант, в результате тратил огромное количество времени, чтобы найти, в чем проблема. Но у меня были небольшие приложения и мне повезло что ошибка проявляла себя. Если же это большой проект КСА УВД и ошибка проявится только при определенных условиях? Например, если начнет работать алгоритм опасного сближения воздушных судов?
Другой пример. В Си точка с запятой — это пустой оператор, который просто не будет выполняться. Поэтому если вы влепите две точки запятой подряд (почистите клавиатуру от крошек!), ничего не будет. Но только не в том случае, когда этот пустой оператор окажется после if:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// корректный Си код, лишняя точка с запятой после первой функции // ничего не портит if (the_signal == clear) { process_track (var1);; show_track (var2); } // лишняя точка с запятой после оператора if: // компилятор Си пропустит этот код, и две функции будут вызываться всегда, // независимо от состояния переменной clear if (the_signal = clear); { process_track (var1); show_track (var2); } |
Для такой ошибки в Си программе КСА УВД диспетчер увидит кучу треков, в том числе ложных, которые на экране появляться не должны.
1 2 3 4 5 6 7 8 9 10 11 12 |
-- корректный Ада код if The_Signal = Clear then Process_Track (Var1); Show_Track (Var2); end if; -- в Ада точка с запятой ожидается только на своих местах if The_Signal = Clear then ; Process_Track (Var1); Show_Track (Var2); end if; -- данный код будет забракован как синтаксически некорректный! |
И в этом случае, компилятор Ада не только укажет на синтаксическую ошибку, но и покажет что точка с запятой избыточна и не на своем месте:
1 2 3 4 |
$ gnatmake uvd.adb gcc-4.6 -c uvd.adb uvd.adb:26:21: extra ";" ignored gnatmake: "uvd.adb" compilation error |
Вы знаете, пока я тестировал эти примеры на своем компе, мне начал нравиться этот язык. Больше всего мне понравилось то, что он имеет встроенные средства многозадачности, чего нет даже в Си. Про многозадачность я напишу в следующий раз, а здесь приведу еще один пример, каких типовых ошибок программирования удается избежать за счет строгой типизации языка Ада. Это очень, очень опасная и распространенная ошибка, которую Си никак не контролирует — выход за границы массива. Если вы просчитались с оценкой размера массива, или совершили ошибку в вычислении индекса, или неправильно организовали цикл… причин может быть множество; в результате вы забираетесь в области памяти, которые принадлежат другим переменным, и эффект опять таки будет непредсказуем.
И полбеды, что это будет именно «эффект», то есть вы будете его наблюдать. Наблюдаете — значит знаете об ошибке. Гораздо хуже, если эффекта не будет, и он проявит себя когда КСА УВД уже в эксплуатации, наступает сочетание нетестируемых факторов…
Ниже программа на Си, которую я также протестировал на своем компе. Она корректна с синтаксической точки зрения, компилятор обрабатывает ее молча, но в ней есть существенный изъян: из-за логической ошибки во втором цикле мы вышли за пределы объявленного массива b и записываем в память уже не значения b, а непонятно что. Никто не схватит нас за руку и не предупредит об этом!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <stdio.h> int a[5]; int b[5]; int main() { int i; // заполняем массив a for(i = 0; i<5; i++) a[i] = i; #if 1 // внимание - мы промахнулись с границами массива b! for(i = 5; i<10; i++) // массив b не получит свои значения b[i] = -2*i; #endif // выводим значения массива a - он испорчен for(i = 0; i<5; i++) printf("[%d] a=%d\n", i, a[i]); } |
Молчание компилятора и результат работы программы:
1 2 3 4 5 6 7 |
$ gcc -o uvd uvd.c $ ./uvd [0] a=-16 [1] a=-18 [2] a=2 [3] a=3 [4] a=4 |
Тадам! Что случилось с нашим массивом a? Точнее, с его первыми двумя элементами? Они затерты вторым циклом. Такой цикл мог располагаться вообще не в нашей программе, или в другом файле, или быть написан позже другим программистом. Сколько дремлющих ошибок в Си коде ждут своего часа, чтобы выйти наружу?
Мотоциклу все равно — если решили сделать крутой разворот и выпали из седла — ваши проблемы. Только посадите ли вы своих детей в такой мотоцикл? И как быть с пассажирами на воздушном судне?
На Аде такой номер не пройдет:
1 2 3 4 5 6 7 8 9 10 |
with Gnat.Io; use Gnat.Io; procedure uvd is A: array(1..5) of Integer; -- Array subscripts 1 to 5. begin for I in 1..5 loop A(i) := I; Put(A(I)); end loop; Put_Line(" "); end uvd; |
Корректный код: компилируем, запускаем, получаем предсказуемый результат:
1 2 3 4 5 6 |
$ gnatmake uvd.adb gcc-4.6 -c uvd.adb gnatbind -x uvd.ali gnatlink uvd.ali $ ./uvd 12345 |
Теперь попробуем выйти за границы массива и попортить что-нибудь в другой области памяти:
1 2 3 4 5 6 7 8 9 10 11 12 |
with Gnat.Io; use Gnat.Io; procedure uvd is A: array(1..5) of Integer; -- Array subscripts 1 to 5. begin -- попытка выйти за пределы массива -- количество итераций больше чем размер переменной for I in 1..6 loop A(i) := I; Put(A(I)); end loop; Put_Line(" "); end uvd; |
Компилируем, запускаем и…
1 2 3 4 5 6 7 |
$ gnatmake uvd.adb gcc-4.6 -c uvd.adb gnatbind -x uvd.ali gnatlink uvd.ali $ ./uvd raised CONSTRAINT_ERROR : uvd.adb:6 index check failed |
Ошибочка вышла! Ада обнаружила что индекс в цикле вышел за границы диапазона. Вот она, прелесть строгой типизации.
Повторюсь, что Си — это прекрасный язык. Но по изложенным причинам совершенно не подходит для критичных приложений, какими являются средства управления воздушным движением (позже я коснусь расширения C++ — все изложенное справедливо и для него, и есть еще дополнительные проблемы). Широко известен набор оправданий, когда выбор несоответствующего инструмента пытаются подменить тем, что «мы будем работать с этим безопасно». Например, оденем шлем на мотоцикле. Или будем забивать гвозди вместо молотка топором, а в инструкции напишем что забивать нужно тыльной частью, а не острым концом, и обяжем всех внимательно следить чтобы острием не заехать себе в глаз.
Когда больше нечего сказать: пришло время оправданий
Итак, послушаем менеджеров, пиарщиков и всех тех, кто продвигает продукты на рынок АС УВД. Вам показалось, что мы забыли программистов? Совсем нет. Это только в менеджерской среде бытуют иллюзии, что качество кода можно поправить инструкциями, внедрением чего-либо типа ISO 9000 или SAP. Поговорите с программистами в курилке: вы обнаружите, что они испытывают такую веселую уверенность в том, что в написанном ими коде наверняка приличное количество ошибок, которые еще ждут своего тестировщика. И это будет наше первое оправдание —
Оправдание №1. Программисты не должны ошибаться
Люди всегда ошибаются. Можно только минимизировать степень этих ошибок. Помните предыдущие таблицы? Это сухая, безразличная статистика. Язык Си развязывает руки и многие вещи считает не «багами», а вашими «фичами». Язык Ада требует от вас ясно выразить то, что вы хотите.
Еще раз: сухая статистика о количестве обнаруженных ошибок на каждую тысячу строк кода:
Количество ошибок / KSLOC | Ада: 0.096 | Си: 0.676 |
Будьте уверены в том, что в такой же примерно пропорции в вашем проекте есть необнаруженные ошибки. Со статистикой бесполезно спорить, ее можно только учитывать.
Оправдание №2. Все ошибки можно обнаружить тщательным тестированием
Дружный хохот программистов в курилке. Для начала, простой вопрос: есть ли в штате разработчиков КСА УВД «Галактика» отделенные от программистов тестеры, какая статистика в багзилле (а есть ли она вообще, система учета tickets?), сколько в премии теряют кодеры на каждую обнаруженную тестером ошибку, сколько в премии теряют тестеры на каждую ошибку, обнаруженную саппортом (а есть ли она в компании вообще, служба поддержки?) После этого можно поговорить про «тщательное тестирование». Кстати, что про это говорит ISO 9000?
Оправдание №3. От выбора языка ничего не зависит. Все решает комплекс мер и правильная архитектура
Это оправдание уже более компетентных людей. Теперь встречный вопрос: как вы собираетесь выстраивать правильную архитектуру на основе Си кода с сотнями заголовочных header файлов? Или может лучше строить архитектуру на языке Ада, который как раз предназначен для больших проектов с миллионами (!) строк кода?
Повторно обращаем внимание на изложенные выше примеры: у вас правильная архитектура основанная на Си коде, а ошибка в одном модуле убивает переменные в другом, хе-хе. На этом вся архитектура заканчивается.
Оправдание №4. Проблемы надежности ПО решаются аппаратным резервированием
То, что аппаратное резервирование серверов решает проблему надежности ПО — иллюзия специалистов которые никогда не писали программ. Если программный сбой возник в основном комплекте сервера, с высокой вероятностью он повторится и в комплекте, который находится в горячем резерве.
Эта особенность была хорошо известна разработчикам VCS Shmid Telecom, которые посвятили этой проблеме значительное время во время общения с нами в офисе компании в Цюрихе. Были разработаны специальные меры для того, чтобы потенциальная программная ошибка не была воспроизведена и при резервировании. С КСА УВД все еще сложнее: нужно сохранить предысторию состояния системы, т.е. все треки и местоположения воздушных судов, которые имели место быть до сбоя.
Оправдание №5. Мы начинали проект уже давно на Си и у нас нет возможности переходить на Ада сейчас
Честный ответ. На языке бизнеса это означает: мы вложили свои деньги в дело и заработаем на своих инвестициях; и неважно, надежный этот код или нет. Желающие могут ознакомиться с нашими сертификатами и актами, которые подписал заказчик. Поскольку это оправдание административного уровня, тут и возразить нечего.
Немного про C++
КСА УВД Галактика написана на C++, поэтому уделим этому расширению языка Си немного внимания. C++ это язык который реализует концепцию объектно — ориентированного программирования. В нем исползуется изоляция реализации методов класса, позволяя сохранить стабильные интерфейсы. Однако защищенность приватных членов класса от изменения снаружи работает только на логическом уровне. На физическом уровне объекты класса точно также располагаются в памяти, как и массивы в примерах которые я привел выше, и они точно также могут подвергнуться изменению.
Кроме этого, у C++ есть серьезные критики. Очень трудно обойти мнение Линуса Торвальдса, автора операционной системы Linux (которая вся написана на чистом Си, без использования С++: интересно почему?), который так высказался об этом языке (выражения похожие на ненормативную лексику смягчены
1 2 3 4 5 |
C++ является ужасным языком. Это обстоятельство усугубляет тот факт, что многие неумелые программисты используют его вплоть до того момента, когда они вляпываются в полное дерьмо. Откровенно говоря, что даже если не было бы причин для выбора именно Си, то возможность держать C++ программистов подальше была бы хорошим оправданием использовать Си. |
Жестко сказано. Что именно не нравится Линусу? Он упоминает
1 2 3 4 |
неэффективные абстрактные модели, которые нужно задавать в C++ в самом начале разработки, когда вы после пары лет движения по пути вдруг обнаружили, что эти модели уже не так хороши, и вы не можете поправить это без переписывания всех программ. |
Это на самом деле так, поскольку все классы в C++ наследуются от самого высокого уровня абстрактных классов, и выбор структуры этих классов очень важен, поскольку под ними со временем возникает целая иерархия и изменить что-либо на верхнем уровне уже невозможно. Как правило, представления о структуре данных и методов в начале проекта и то, к чему мы приходим в конце проекта, существенно разнятся. На это нам и указывает Линус, и к его мнению стоит прислушаться: как никак, ядро Линукс это огромный проект, и кому как не ему знать, как строится архитектура таких проектов.
Еще одно замечание системного уровня. Этот уровень для нас очень важен, поскольку одну программу может написать любой, а комплекс требует совсем других компетенций и опыта:
1 2 3 |
Единственный способ сделать проект C++ на системном уровне хорошим, эффективным переносимым - это ограничить себя до вещей, которые и так доступны в C. |
Тоже очень интересная мысль. Значит, начиная в C++ мы постепенно выбрасываем из него вещи, которые мешают быть нашему проекту быть переносимым и эффективным, и в результате приходим к тому, что используем функционал языка Си. И больше никаких классов.
Кстати, замечание: модель объектно — ориентированного программирования не тождественна классам. Ее можно реализовать и на Си.
В этих словах Линуса можно предсказать судьбу C++ проекта КСА УВД Галактика: со временем рамки абстрактных классов верхнего уровня станут тесными, и софт ждет переработка на уровень вниз — до языка Си. Если к этому времени он не будет портирован на Ада.
Послесловие
Вот и подошло к концу наше небольшое исследование. Почему мы обратили внимание именно на КСА УВД Галактика? Причина в том, что другие поставщики систем УВД не позиционировали свои продукты как современные, передовые и соответствующими правилам Евроконтроля. А поскольку для Галактики написано что она современная, нам захотелось больше узнать про лучшие отечественные примеры.
Вернемся еще раз к тому, что написано на сайте поставщика Галактики про качество и безопасность. Там есть «вишенки» про «соответствие международным стандартам ED 153, DO278/ED 109 (SWAL 3 and 4)», но нет «тортика»: «ПО разработано на языке Ада». Поэтому вишенка как-бы повисает в воздухе: как можно обеспечить соответствие указанным стандартнам безопасности разрабатывая программы на Си?
Известные компании Thales и Indra указывают, что разработка средств УВД ведется на языке Ада. Это точно торт который нужен; к нему не стыдно присовокупить вишенку про то, что надежность ПО в соответствии с требованиями DO278/ED 109 обеспечена.
Безопасных вам полетов!
Вот не стал бы сравнивать КСА (особенно в ВВП) с чем-либо встраиваемым в самолет-поезд. Слишком уж разные вещи. КСА УВД по регламенту локаторов может несколько часов простаивать. Мне диспетчера сами говорят «Мне нужна радиостанция(аварийная) и простой телефон для выхода на сеть ТфОП — то что какие-то «сервера» чего-то не работают — ну и бес ними, но замечание я вам завтра напишу :-Р.». Сугубо уж философский вопрос. Тут и к заказчику можно претензии высказать — кто и как составлял ТЗ, как тестировали, как принимали, какие условия поддержки.
Про резервирование согласен — вроде эта задача со 100% гарантией не решаема(проблема «двух армии вроде» или как-то так), проще иногда иметь 2 сервера работающих параллельно, чем отслеживать, кто «главный», а «нет».
Конечно, КСА может постоять, если интенсивность полета низкая. В крупных центрах без нее уже никак. И тут дело даже не в том, что КСА УВД может «отключиться» из-за программного сбоя. Хуже ситуация когда она вроде бы работает, но деверять ее данным нельзя.
В КСА УВД «Галактика» резервирование сделано именно так: работает основной сервер, второй — в горячем резерве, работает параллельно. Третий сервер — в холодном резерве. При отказе основного сервера второй подхватывает текущую картинку, поскольку у него есть предыстория. Если накроется второй, тут уже надо включать третий, и всю картинку отрисовывать с нуля.
Вот эта схема горячего резерва хорошо работает при аппаратном отказе. Если у основного сервера возникла проблема в ПО, т.е. он попал на ветку алгоритма с ошибкой при определенных входных данных, то сервер горячего резерва точно также попадет на эту ошибку, поскольку он работает параллельно с основным. Поэтому для горячего резерва нужно придумывать алгоритм посложнее.
Крупные центры, скорее всего, должны биться на сектора, которые сильно независимы друг от друга — хотя я не силен в резервировании. Мне так еще не нравиться закрытость интерфейсов-протоколов КСА, крайне скудные логи и т.д. (я не про «Галактику»).
Все равно, мне кажется, язык все-таки инструмент — мастер главное(и заказчик, который четко знает, что ему нужно), тут спор что лучше, дремель или стамеска. Было бы в ТЗ условие на полный рестарт сервера менее чем за минуту — возможно С++ не выбрали. Если бы разработчик не работал строго с VS (так как потрачены многие килобаксы за проф. лицензию), то может сторонние компиляторы выявили большее кол-во узких мест. Ошибки про двойное «==» можно проверять хоть тупо «grep»-ом исходного кода. Как проводилось тестирование опять таки(я так слышал, как разработчики терминала речевой связи оправдывались, что для поиска ошибок им нужно с десяток девушек операторов, которые будут постоянно звонить друг-другу по громкой связи, т.е. даже речи об программном эмуляторе не было).
Вы правы, язык это только инструмент и всего лишь одна из составляющих надежности. Даже при самом изощренном тестировании есть вероятность, что ошибки остаются. И с этим ничего не поделать
Проверил ошибку = и == в двух компиляторах. Один выдал ошибку второй предупреждение.
Ошибка if(); действительно существует, хотя элементарно может быть исправлена выдачей предупреждения ( мне даже кажется, что это я где то видел)
Это только одна из потенциально возможных ошибок навскидку. Подобного рода рискованных мест может быть много.
Когда собирается большой проект и к тому же в нем есть модули третьих сторон, весь терминал в предупреждениях компилятора. За ними не уследить
Нашел ключ gcc при котором выдается предупрежднение при подобном присванивании:
-Wparentheses
Предупреждение звучит так:
warning: suggest parentheses around assignment used as truth value [-Wparentheses]
выход за границу массива интереснее. Но надо его проверять не в цикле, а в параметре функции.
Даст ли ада ошибку в таком случае?
Как ада узнает диапазон значений какой либо произвольной переменной?
Ну и в си этой ошибки избежать элементарно — достааточно всегда проверять индекс массива.
В Ада когда мы задаем тип переменной, этим самым мы вводим ряд ограничений на ее значения. И проверка соответствия производится каждый раз, когда мы работаем с этой переменной, без нашего участия.
Конечно, в Си можно проверять индекс массива при каждом обращении к массиву. Но это во первых перегружает код, во вторых проблема переходит в организационную плоскость — программист в большом проекте может просто забыть выполнить это правило. В третьих, если есть необходимость делать каждый раз такую проверку, то логично предположить что она должна делаться на уровне языка
>>Больше всего мне понравилось то, что он имеет встроенные средства многозадачности, чего нет даже в Си.
Несколько строчек на асм — и в си вы получаете любую форму многозадачности.
Можно использовать ассемблерные модули. Тут сразу налетаем на машинно — зависимый код (проблемы при портировании на разные платформы). На ассемблере возможность сделать ошибку гораздо выше, чем в Си.
Опять таки хочется, чтобы все было реализовано на уровне языка, стандартным и надежным способом.
Какой же бред! Зачем вы это пишете? Проталкиваете Thales, который в Россию не пустили?
Кто так пишет код? Я не говорю на с++, вообще на любом языке. Хоть ада, хоть с/с++, хоть hdl языки, хоть жавы всякие…. неважно…. так код писать не допустимо на любом языке… так даже недопустимо писать программы не для компьютера, а для людей, например программу партии/экзамена/фестиваля и т.п.
Поясню.
// лишняя точка с запятой после оператора if:
// компилятор Си пропустит этот код, и две функции будут вызываться всегда,
// независимо от состояния переменной clear
if (the_signal = clear);
{
process_track (var1);
show_track (var2);
}
Это детские ошибки и компилятор даст ворнинг…. и вы правы…. можно допустить такую опечатку в коде и отгрести (по крайней мере в с/с++). НО!!! Как пишется код на любом языке…. пишим….
if (the_signal = clear);
{
process_track (var1);
show_track (var2);
}
после написания ОБЯЗАТЕЛЬНО проверяем выполнение. Как проверяем… можно написать тест и проверить, но можно прямо в коде без всяких внешних тестов проверить все варианты. те я такой так проверяю после написания, пишу
the_signal = clear;
var1 = 1; var2 = 5;
if (the_signal = clear);
{
process_track (var1);
show_track (var2);
}
Собираю, запускаю, проверяю…. должен зайти под иф и выполнить process_track(), а также увидеть show_track(). Если нет show_track(), то что-то не так…. либо с show_track, либо я не попадаю под if. После того, как я исправлю ошибки… получаю
the_signal = clear;
var1 = 1; var2 = 5;
if (the_signal == clear)
{
process_track (var1);
show_track (var2);
} Вот тут всё заработает…. для достоверности еще проверю с такими параметрами
var1 = 1; var2 = 15;
потом с такиим
var1 = -1; var2 = 150000;
и с такими
var1 = 10.23; var2 = -15; проверю на макс минимум вар1 и вар2, а также с входом за пределы допустимых значений.
Потом пишу перез if
the_signal = clear+10;
Не должен зайти под if.
Это не займёт много времени и каких-то сверхзатрат.
более того если будет код такой
if (the_signal == clear)
{
process_track (var1);
show_track (var2);
}
else if (the_signal => MAX)
{
process_track (var3);
show_track (var4);
}
else if (the_signal < 0)
{
abort();
}
я обязательно проинитю the_signal перед if значениями clear, MAX, MAX+1, -1 и проверю заход программы в каждую ветку if.
Это не оправдание программиста С++, это замечание программиста. Я заход в каждый if проверю ОБЯЗАТЕЛЬНО хоть на си/c++, хоть на java, хоть на ада, даже если компилятор мне не выдаст ошибок. А если делать заходы во все ветки, то всякие двойные ;;, и = вместо == тут же обнаружатся.
Все ваши доводы высосаны из пальца.
ps более того… в verilog есть операторы =, ==, ===, а также есть "<=" оператор сравнения меньше или равно, а есть "<=" оператор присваивания. Можно присвоить так:
var2 = 15;
а можно присвоить (не сравнить, а присвоить переменной var2 значение 15)так
var2 <= 15;
и блок будет по разному работать.
Там вообще дров наломать можно. Но ни кто не говорит что верилог плох. Пишут на нем. Тестируют. Проверяют. Симулируют. И все нормально.
Очень эмоционально ) Понимаю, что нужно блюсти честь мундира и прочее, но как говорится истина дороже )
Сразу ловлю вас на слове: «Это детские ошибки и компилятор даст ворнинг….»
Демо tst.c:
#include
#include
int main(int argc, char* argv[])
{
int a = atoi(argv[0]);
// внимание!
if(a = 1)
printf(«Warning 1\n»);
else
printf(«Warning 2\n»);
}
Компилируем и собираем:
$ gcc -o tst tst.c
И тишина… как видим, warnings может и не быть, как и сказано в статье.
То что вы пишете дальше, только подтверждает основной тезис статьи: надежность разработки ПО конечно зависит от качества вашей работы, но для критичных приложений надеяться только на квалификацию программиста недопустимо.
«я обязательно проинитю the_signal перед if значениями clear, MAX, MAX+1, -1 и проверю заход программы в каждую ветку if»
— вот это «обязательно» мне очень нравится ) Ада поправит вас, если по каким-то причинам вы оказались не столь обязательными.
И хорошо бы в профессиональной дискуссии придерживаться принятой терминологии. «проинитю» звучит как-то по любительски.
«Ада поправит вас, если по каким-то причинам вы оказались не столь обязательными.» — не поправит. если вы написали одну или несколько веток ветвлений и не проверили заход в каждую, ада (или любой язык) за вас это не сделает.
Компилируем и собираем: в c++
Warning[Pe187]: use of «=» where «==» may have been intended ../tst.cpp 183
в с
Warning[Pe187]: use of «=» where «==» may have been intended ../tst.c 215
«Компилируем и собираем:
$ gcc -o tst tst.c
И тишина…» — что за компилятор и ОС?
«Сразу ловлю вас на слове: Это детские ошибки и компилятор даст ворнинг….» — вы не правильно поняли. вы попытались одно утверждение опровергнуть, но тут их два, повторюсь
1)Это детские ошибки
2)компилятор даст ворнинг
«проинитю» звучит как-то по любительски. П Р О И Н И Ц И А Л И З И Р У Ю — УЖАС!!! Пока это слово напишешь…. как раз таки в проф.терминологии инитят, комитят и пушают, ловят ворнинги и ероры. Проф сленг. Буду его придерживаться, мы же [s]с вами[/s] не кухарки.
«// внимание!
if(a = 1) //ошибка1» — вообще такое ВНЕИМАНИЕ очень настораживает…. понимаете… вам нужно проверить, чтоб а было больше нуля…. т.е. вот правиольный код
if(a > 0)
но если допускать ошибки аналогично вашей, то можно написать
if(a<0) — и ни один компилятор в мире ни какого языка не поправит вас на этапе компиляции.
а можно ошибиться на написать так
if(a= 1234) //ошибка3
вместо if( a > 0)
Если программист допускает ошибки подобные ошибка1, ошибка2 и ошибка3 — он вообще не программист и его не допустят до программирования. Зачем от таких говорить? Давайте поговорим о детях в яслях. Это всё ещё в школьном кружке учиться. Можно допустить опечатку, но проверкой захода в ветки это всё тут же правиться (на любом языке, а не с/с++).
«вот это «обязательно» мне очень нравится» ))))) Так это все делают. На любом языке. Программист обязан проверить работу своей программы после написания. Программист обязан проверить работу каждой ветки программы. Или вы думаете, что программы пишутся, один раз компилируются и сразу отдается потребителю без проверки?
Есть же у вас статьи типа «Занимательная стоматология», или про Игры, Алхимию…. пишите про это… не нужно вам писать про программирование, если вы [s]в нем не разбираетесь[/s] думаете, что в программах могут быть ошибки типа if(a=0).
Специалист по ПО не знает компилятор gcc… видимо дальше продолжать дискуссию нет смысла.
Я бы посоветовал вам пройти школу не в челябинском филиале Азимута, где нет задач хорошего уровня для программиста (АДУ не могут доделать уже лет 10), а в хорошей команде коммерческой разработки ПО. Хотя для начинающего с юношеским максимализмом может и пойдет — на первом этапе ) Хотя бы до уровня Устинова, приглашенного на работу Microsoft и убывшего на ПМЖ в США )
Да, еще по поводу проф. терминологии: вы не представляете как режет уши смесь французского с нижегородским после хорошего английского зарубежных партнеров. В документации тоже будете писать про ворнинки и ероры? )
На этом предлагаю поставить точку.
Увы, но Устинов теперь решает задачи на порядки проще, чем решал в Челябинском филиале.
По поводу хорошего уровня — считаю, что у Евгения очень хороший уровень, как у программиста.
По поводу АДУ, в архитектуре которого есть и Ваша заслуга (оценок тут давать не буду — не вижу смысла), оно работает, имеет сертификат и им пользуются. Разумеется, без проблем не бывает, но они решаются.
Возможно, что задачи которые решает Устинов, выглядят проще. В любом случае работа в большой профессиональной компании это объективный показатель для HR.
По поводу АДУ замечу, что она построена далеко не оптимальным образом, поскольку в то время филиальная структура только создавалась, для разрабатывающих подразделений не было ни единого плана работ, ни технической политики и даже коммуникаций по горизонтали. Поэтому о том чтобы сделать единый протокол обмена с единым АДУ для всех изделий не могло быть и речи. Было принято временное и плохое, но единственно возможное в тех обстоятельствах решение — нанизать на живую нитку весь зоопарк решений с тем, чтобы в последствии сделать все правильно. Но похоже все так и осталось.
Показатель для HR на мой взгляд — это только оценка, иногда не корректная и предвзятая. Прямая корреляция этого показателя с кошельком — согласен!
Работа в большой профессиональной компании — это только слова. Работа над чем в этой компании — вот что на мой взгляд важно.
Думаю, что Паша с его головой будет двигаться и расти, зависимости от места работы тут тоже не вижу — это его личное качество, его способность.
Скорость роста скорее всего будет выше.
Теперь за АДУ 🙂
Азимут растёт, пополняется филиалами. Найти гения, который скажет, как правильно расти и создаст четкие правила — увы нет и не будет.
Рост идет, идет стыковка и программных продуктов и тут тоже нет гениев, которые дадут сразу правильные рецепты учитывающие реальность.
Чтобы быть таким гением, надо понимать и всю внутреннюю кухню до винтика и внешний вектор. К сожалению есть и фактор оттока программеров (как и везде), люди ведь тоже растут на проектах и перерастают их 🙂
Главное, как мне кажется — то, что рост есть, а остальное выбирает каждый за себя, расти вместе и помогать росту или сидеть в сторонке и искать минусы.
Хотя такая функция тоже полезна для роста, если её правильно использовать.
Работа в большой профессиональной компании — это только слова. Работа над чем в этой компании — вот что на мой взгляд важно.
Золотые слова. Дмитрий, вы программист в Челябинском филиале который не так давно уволился из Азимута? )
К вопросу о тестировании КСА УВД Галактика, то в штате даже нет тестиров, не то что отдела для тестирования, любой код правится в ручную, без тестирования и на объекте, так что говорить о каком то качестве продукта даже не приходится
Это проблема маленьких коллективов которые выросли но не масштабировались. В зрелой группе по разработке ПО должен быть специалист в предметной области, системный архитектор, программисты, кодеры и само собой тестировщики с системой сопровождения тикетов типа Багзилы. Плюс еще внедрение и поддержка