Чертова дюжина проблем программной инженерии

Программная инженерия превратилась сегодня в дисциплину со множеством направлений: тестирование, программирование, проектирование и т. п., однако она продолжает самостийно развиваться вне традиций — в какой-то мере это и ремесло, и искусство, и логика.

Джеффри Воас

Программная инженерия — это по определению прикладная область и частично практический предмет, однако научные открытия и знания не являются основными мерилами ее успеха: программные инженеры-практики главным образом занимаются созданием и развитием программных систем, стараясь придерживаться определенных темпов, обеспечивать достаточное качество и оставаться в рамках бюджета. Мерой успеха здесь является объем созданных концепций, методик и процессов, позволяющих разработчикам решать задачу развития программного обеспечения. Кроме разработки и сопровождения ПО, для данной задачи характерен еще ряд подзадач: анализ требований, разработка спецификаций, реализация, интеграция и аттестация.

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

Может ли теория улучшить программную инженерию?

В недавней статье Ивара Якобсона и Яна Спенса по теории программной инженерии говорится: «Наша важнейшая задача — понять, как строить качественное программное обеспечение». Но что именно подразумевается под словом «качественное»? Есть ли методы, помогающие отличить качественное ПО от не очень? Даже простые вопросы вроде этих опираются на критерий качества.

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

  • ввод точной и адекватной терминологии (например, более удачных терминов, чем «качественный» для указания качества ПО);
  • разработка методов построения ПО достаточного качества;
  • идентификация методов измерения и оценки как самого ПО, так и эффективности процессов, концепций и инструментов, используемых для его разработки.

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

Ремесло, наука или инженерная дисциплина?

Разобравшись в различиях между ремеслом, научной теорией и инженерным делом, можно понять роль теории в инженерии:

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

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

SE2004: рекомендации по обучению специальности «Программная инженерия»

Во всем мире университеты разрабатывают курсы по программной инженерии, дополняющие существующие программы по информатике и компьютерной инженерии. Чтобы сформулировать принципы составления эффективного учебного плана, в рамках проекта Computing Curriculum разработан набор рекомендаций Software Engineering 2004.

Тимоти Летбридж и др.

Ремесло и инженерия имеют много общего, поскольку у них схожие цели: создание конструктивных решений практических проблем изготовления изделий и предоставления услуг. Соответственно граница между ремеслом и инженерией размыта, например существует мнение, что разработка ПО сегодня в большой степени ремесло. Однако согласно определению ремесло пользуется традиционными методами, а поскольку разработка ПО еще молодая область, у нее нет достаточного количества таких методов. В некоторых отношениях данная дисциплина эмпирическая, опирающаяся на методики, которые нельзя назвать хорошо проверенными. Эволюция традиционных методов требует времени, а сфера ПО все еще стремительно развивается.

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

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

Зачем нужна теория?

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

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

Теория и методы

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

Как и другие дисциплины, программная инженерия имеет множество аспектов: люди, управление и команды; экономика и расходы; методология, инструменты и процессы разработки; факторы взаимодействия человека с машиной; технологии (оборудование, операционные системы и языки программирования).

Исследователи могут применять теорию для интерпретации и разъяснения препятствий, мешающих инженерной практике, а также предлагать конструктивные обоснования инженерных методов и инструментов. То, насколько теория и методы важны для инженерии, очевидно на примере разработки компиляторов. Благодаря системному применению теории в данной области, в том числе бесконтекстной грамматики и генераторов, эта область разработки ПО стала зрелой одной из первых.

Мифы о программной инженерии

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

Хоссейн Саедян, Доналд Берет, Нэнси Мид

Видную роль в некоторых аспектах программной инженерии также играют логические теории, позволяющие разработчикам пользоваться математической логикой для решения формальных задач. Исследования в области формальных методик необходимы, они могут приводить к открытиям, а в конечном итоге к созданию надежных инженерных методов. Однако существует значительный разрыв между исследованиями в области формализации и разработкой удобных методов. Несомненно, такие методы также требуют тщательного анализа масштабируемости, простоты и широты применения, КПД и эффективности.

Несмотря на описанные исследователями преимущества применения формальных методов в некоторых областях программной инженерии, существуют некоторые доводы против их полезности. Формальные методы:

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

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

Теория и образование

Обучение программных инженеров без преподавания теоретических основ немыслимо, и, даже если какие-то теории неприменимы непосредственно в практике инженерии, они создают базу для понимания ее основ. В качестве примера можно привести логику утверждений. Хотя формальные доказательства программ посредством утверждений на практике не используются, изучение троек Хоара, инвариантов цикла и доказательств завершимости имеет ценность в качестве теоретического упражнения. То же касается алгебраических типов данных, реляционных моделей данных и модульных моделей программных архитектур.

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

Эволюция программного обеспечения — это инженерная дисциплина, основанная на информатике, и ряд ее теоретических разделов важны для программной инженерии. Очевидно, что для программных инженеров имеют значение такие классические разделы знаний, как формальные языки, вычислимость и теория сложных вычислений. Исследователи не могут разрабатывать масштабные программные системы без знания ограничений вычислимости и разрешимости. Быстродействие невозможно обеспечить без понимания принципов вычислительной сложности. А инструменты программной инженерии для моделирования или программирования нельзя создавать без познаний в формальных языках.

Методы описания семантики языков программирования, формальной спецификации программы и ее верификации являются элементами теории программирования. Определенно программирование в его узком понимании — это основа программной инженерии, но не программная инженерия как таковая. В реальности программная инженерия касается программирования и разработки в более широком смысле. Некоторые теории, закладывающие основы программной инженерии, имеют непосредственное отношение к программированию в широком смысле. Примерами могут служить методы моделирования таких ключевых аспектов программных систем, как требования, архитектура, интерфейсы, многократно используемые модули и качество.

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

Хотя формальные методы не всегда применимы в непосредственной практике программной инженерии, они помогают в понимании ее базовых принципов и концепций. Нельзя, например, разобраться в понятиях корректности, спецификации или верификации без знания соответствующей теории. Даже если на практике строгое исполнение этих процессов согласно формальным методам не обязательно, по крайней мере их понимание будет полезным.

Еще одной важной основой программной инженерии является развившаяся совершенно независимо от нее математическая логика — между вычислениями и математической логикой есть тесная взаимосвязь, и многие задачи программной инженерии тесно связаны с логикой. Причина очевидна: ПО по своей природе является формальным артефактом, поэтому вычислительное оборудование может исполнять программы, интерпретируя их независимо от человека. Следовательно, ПО проявляет поведение и свойства, доступные для формального анализа, даже если какая-то концепция программирования не формализована или программа написана на нестандартизованном языке или исполняется с помощью нестандартизованного интерпретатора. При этом ПО принципиально отличается от других технических артефактов. В отличие от традиционных инженерных дисциплин, программа нематериальна — это чистая логика, она описывает динамическое поведение статическими средствами с использованием строгих формализмов (языков программирования).

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

Теория в программной инженерии

Инженеры ПО применяют как научные (математические, экономические и социальные), так и практические знания при проектировании и построении программных систем, а теория может помочь им избежать повторения прежних ошибок. Но грустно видеть, насколько общепринятые теоретические принципы игнорируются в прагматических задачах, таких как разработка UML и Java. Одно из досадных упущений программной инженерии состоит в том, что она пока не сумела взаимовыгодным образом свести воедино теоретические знания и практическую работу.

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

Тем не менее теории программной инженерии за последние 40 лет получили колоссальное развитие, особенно в области разработки спецификаций и верификации, архитектуры и проектирования, тестирования, управления программными проектами и экономики ПО. Однако до появления общепринятых и полных теоретических основ еще далеко, и требуется еще немало труда над теорией, чтобы ее можно было применять к колоссальным проектам разработки ПО будущего. Легко предсказать потребность в сооружении обширных программных систем, создании больших семейств программных продуктов и киберфизических систем. Теоретические основы со временем станут неотъемлемой частью выполнения функциональных и нефункциональных требований, касающихся безопасности, защищенности, надежности, удобства использования и сопровождения программных систем, в особенности сильно распределенных.

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

Теория, основанная на опыте

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

Теория, созданная отдельно от практики

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

От прикладных методов к теории

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

Между перечисленными подходами есть важные различия. Опасно полагать, что теория, не разработанная в тесном взаимодействии с практиками, будет иметь практическую пользу. Более перспективным был бы итеративный подход, состоящий в поочередной разработке элементов теории и применении их на практике. Разработка полезной теории требует определенных навыков ведения теоретической работы. Не все программные инженеры, обладающие глубокими практическими познаниями, располагают достаточным опытом научной работы, чтобы выразить эти познания в форме адекватной теории.

Решение практических вопросов

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

В 80-х годах на основании наблюдения о том, что ряд правил дедукции в линейной логике имеет сходство с явлениями в параллельных системах, некоторые исследователи утверждали, что линейная логика способна улучшить теорию параллелизма. Однако в конечном счете линейная логика ничего не дала ни теории, ни практике проектирования параллельных и распределенных программных систем. Еще один пример — теория частично упорядоченных множеств Вона Прэтта. Хотя она стала интересным этапом в понимании структуры параллельных процессов, проникновение в подробности частично упорядоченных множеств и пространств Чу на практике оказалось бесполезным и в конечном итоге ничего не дало решению инженерных проблем.

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

Несомненно, полезно разрабатывать концепции и обосновывающие их теории в поддержку решения определенных задач программной инженерии, таких как разработка спецификации, проектирование и верификация. Но это можно делать математическими методами, позволяющими создавать теории, которые вносят вклад в понимание предмета инженерии и доказывают концептуальную верность ее методов. Если теоретики не учитывают практические проблемы, их работа бесполезна с прагматической точки зрения и не найдет прямого применения на практике. Этому есть несколько причин: мир программной инженерии далек от совершенства, и практическая эволюция ПО требует множества компромиссов — не только из-за нехватки образования у инженеров, но и ввиду многих практических дефектов оборудования, инструментальных средств и организационных структур. Создание стройной теории для бессистемного мира практики — весьма трудная задача.

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

***

Каждая инженерная дисциплина имеет собственный научный фундамент. Электронная инженерия и машиностроение основаны на физике, программная инженерия базируется на логике и теории информации и вычислений. Необходимо четкое понимание того, что в перспективе программная инженерия не сможет существовать без собственной стройной научной теории. Факт в том, что программная инженерия требует знания теории, широты ее возможностей и ограничений. Разработка теории, в свою очередь, нуждается во всеобъемлющем понимании практики, ее потребностей и нерешенных проблем. Структурированное изложение теории и ее связи с инженерией программных систем является обязательным элементом преподавания предмета программной инженерии.

Манфред Брой ( broy@in.tum.de ) — профессор Мюнхенского технического университета.

Manfred Broy. Can Practitioners Neglect Theory and Theoreticians Neglect Practice? IEEE Computer, October 2011, IEEE Computer Society. All rights reserved. Reprinted with permission.