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

Сложность разработки программного обеспечения обусловлена когнитивными и социальными аспектами профессии. В течение последних трех лет мы преподавали курс «Гуманитарные аспекты программирования» в Технологическом институте Technion (Израиль) и в Школе информатики при Университете Карнеги—Меллона. Курс нацелен на то, чтобы расширить представление студентов-программистов о богатстве и сложности гуманитарных аспектов разработки, а также о проблемах, дилеммах, вопросах и конфликтах, с которыми они могут столкнуться в своей работе [1]. Курс позволяет развить у студентов рефлексивные мыслительные процессы и дать им понять, для решения каких задач требуется абстрактное мышление.

Рефлексия и абстракция в программировании

Рефлексивный и абстрактный способы мышления играют ключевую роль в обучении программистов и в практике разработки программного обеспечения.

Рефлексивное мышление

Концепция критического осмысления практической деятельности (reflective practitioner perspective), предложенная Дональдом Шоном [2, 3], ориентирует специалистов-практиков (архитекторов, менеджеров, музыкантов и др.) на переосмысление своей работы как в ходе творческого процесса, так и после его завершения. Эта концепция основана на предположении, что такая рефлексия повышает профессиональное мастерство и продуктивность деятельности. Анализ дисциплины программирования и видов входящих в нее работ делает обоснованным применение данной концепции в программировании вообще и при обучении программистов в частности [4, 5]. В контексте программирования важность рефлексии как способа мышления обусловлена главным образом сложностью процесса разработки программных систем, а также важной ролью налаживания коммуникаций между членами группы для успешного развития программной системы.

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

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

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

Студийный подход к обучению, применяемый в Школе информатики при университете Карнеги—Меллона [6, 7], стимулирует рефлексивные процессы. Курс, который здесь представлен, интегрирует эти процессы в общий процесс обучения программистов.

Абстрактное мышление

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

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

Абстракция является неотъемлемой частью процессов программирования, поэтому при обучении студентов нужно подчеркивать ее важность и давать четкое представление о выгодах, получаемых при использовании данного подхода. Именно поэтому абстракция была выбрана в качестве центральной темы курса «Гуманитарные аспекты программирования». Абстракция может быть выражена разными способами, но все они ведут к преодолению когнитивной сложности путем игнорирования несущественных деталей на определенных стадиях решения проблемы. Основываясь на [1], мы выделяем три способа выражения абстракции.

  1. Заметить нечто общее в группе объектов и выразить это в одном абстрактном понятии. В таких случаях абстракция ведет к поиску общих характеристик в множестве объектов и к игнорированию несущественных различий между ними. Мы можем выразить эти характеристики в виде математического понятия либо класса в объектно-ориентированном программировании и т.д. В этом смысле абстракция представляет собой отношение «многих к одному». Например, иерархия млекопитающих выражает абстракцию, в которой на верхних уровнях различия между животными игнорируются, а на более низких — учитываются. Шаблон проектирования (design pattern) является примером выражения подобной абстракции в контексте программирования [9].
  2. Для описания конкретного решения выбрать соответствующий уровень абстракции языка. Этот язык не должен базироваться на инструментах, предоставляемых языком программирования, который используется для фактической разработки программ. В данном случае абстракция помогает разработчикам размышлять о проблеме в соответствующих концептуальных терминах, отвлекаясь от специфических терминов языка программирования. Если бы они не использовали подобных абстракций, компьютерные языки вынуждали бы их копаться в несущественных деталях на ранних этапах проекта, «брали бы под контроль» процесс программирования. Абстракция заполняет собой промежуток между естественным языком и языком программирования. Эта идея находит отражение в эволюции языков программирования. На ранних этапах развития они сильно отличались от человеческих, но для выражения своих идей на современном языке программирования уже можно выбрать способ, значительно более близкий к естественному языку.
  3. Применить абстракцию для описания объектов в соответствии с их характеристиками, отвлекшись от их устройства или принципов работы. Энтони Хоар [10] поясняет, что абстрактная команда определяет желаемое поведение компьютера, не расписывая в деталях, как оно достигается. Эту идею можно выразить, например, путем написания единого набора инструкций для манипулирования объектами разных типов, в котором различия в способах воздействия на разные объекты будут определяться нижними уровнями абстракции. Данный подход реализуется путем установки барьеров абстракции [11].

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

Описание курса

В курсе «Гуманитарные аспекты программирования» студентам предлагаются конкретные задачи, ориентированные на рефлексию и абстракцию.

Природа программирования

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

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

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

Методы программирования

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

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

Коллективная работа

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

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

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

Этический кодекс программирования

На четвертом занятии рассматриваются этические понятия, в частности Этический кодекс программиста (www.computer.org/tab/seprof/code.htm). Главное внимание уделяется повышению способности студентов в процессе разработки предвидеть ситуации, в которых возможен ущерб с этической точки зрения, и обсуждаются способы, позволяющие избежать таких ситуаций.

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

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

Абстракция может быть проиллюстрирована на примере оригинального текста Этического кодекса. В его преамбуле утверждается: «... краткая версия Кодекса на высоком уровне абстракции суммирует стремления. Статьи, включенные в полную версию, содержат примеры и детали того, как эти стремления изменяют образ действий профессиональных программистов. Детали без стремлений могут стать формальными и утомительными; стремления без деталей будут звучными, но пустыми; стремления и детали вместе образуют согласованный Кодекс».

Программное обеспечение как продукт

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

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

Интернациональный взгляд на программирование

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

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

Понимание программ

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

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

На данном занятии абстракция играет центральную роль, поскольку некоторые теории восприятия программ используют ее как организующую идею [12]. Уместность абстракции в таком контексте очевидна. Для восприятия программы необходимо научиться свободно переходить с одного уровня абстракции на другой, для чего требуется высокий уровень понимания. Чтобы углубить представление студентов о роли абстракции в этом процессе, мы просим их разобраться с вопросами типа «как понимание разных уровней абстракции улучшает ваше восприятие программы?»

Процесс обучения программированию

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

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

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

Взгляды на программирование

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

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

Принципы разработки

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

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

Гуманитарные аспекты программирования

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

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

История программирования

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

Анализ конкретных примеров

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

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

Литература
  1. J. Tomayko, O. Hazzan, Human Aspects of Software Engineering. Charles River Media, 2004.
  2. D.A. Schon, The Reflective Practitioner. BasicBooks, 1983.
  3. D.A. Schon, Educating the Reflective Practitioner: Towards a New Design for Teaching and Learning in the Profession. Jossey-Bass, 1987.
  4. O. Hazzan, The Reflective Practitioner Perspective in Software Engineering Education. J. Systems and Software, 2002, vol. 63, no. 3.
  5. O. Hazzan, J. Tomayko, The Reflective Practitioner Perspective in eXtreme Programming. Proc. XP Agile Universe, LNCS. Springer Verlag, 2003, vol. 2753.
  6. J. Tomayko, Teaching Software Development in a Studio Environment. Proc. SIGCSE Technical Symp., ACM Press, 1993, vol. 23, no. 1.
  7. J. Tomayko, Carnegie Mellon?s Software Development Studio: A Five-Year Retrospective. Proc. SEI Соя/l Software Eng. Education; www.contrib.andrew.cmu.edu/usr/ emile/studio/coach.htm.
  8. J. Kramer, Abstraction-Is It Teachable? ?The Devil Is in the Detail?. Keynote address, Proc. 16th Conf. Software Eng. and Training, IEEE Press, 2003.
  9. E. Gamma et al., Design Patterns, Addison-Wesley Professional. 1995.
  10. C.A.R. Hoare, Mathematics of Programming. Byte, Aug. 1986.
  11. H. Abelson, J. Sussman, Structure and Interpretation of Computer Programs. MIT Press and McGraw-Hill, 1986.
  12. A.M. Vans, A. von Mayrhauser, S. Gabriel, Program Understanding Behavior during Corrective Maintenance of Large-Scale Software. Int?l J. Human-Computer Studies, 1999, vol. 51.
  13. P.M. Senge, The fifth Discipline: Fieldbook, Currency. 1994.

Орит Хазан (oritha@techunix.technion.ac.il) — старший лектор факультета научно-технического образования в Технологическом институте Technion (Израиль). Джеймс Томэйко (jet@cs.cmu.edu) — профессор Школы информатики при университете Карнеги—Меллона.


Шесть шагов построения примера

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

  • Шаг 1. Выберите и обдумайте тему обсуждения, которую вы находите интересной и уместной.
  • Шаг 2. Проанализируйте тему. Определите, достойна ли она стать центром конкретного примера. Задайте себе следующие вопросы. В деятельности какого рода участвуют разработчики в рамках выбранной темы? С какими гуманитарными аспектами программирования связана эта тема? Она относится к группе в целом или к отдельным членам группы? Если ответы на подобные вопросы показывают, что тема достаточно богата и может быть связана с различными проблемами разработки ПО, то она «достойна» стать центральной для конкретного примера.
  • Шаг 3. Продумайте возможные ситуации. Укажите по меньшей мере две ситуации в практике программирования, имеющие отношение к выбранной теме. Это поможет определить, существуют ли конкретные ситуации, в которых исследуемая тема выражается в ощутимой форме.
  • Шаг 4. Опишите конкретный пример. Обязательно включите в него основные проблемы, которые вы хотите рассмотреть, и сделайте пример как можно более ярким.
  • Шаг 5. Проверьте область применения. После описания и редактирования конкретного примера определите, можно ли ввести в него другие, связанные с ним темы. Удостоверьтесь в сохранении основной направленности. Правильно ли конкретный пример отражает главную идею, которую вы хотите донести? Ясны ли связи между темами примера?
  • Шаг 6. Разработайте интересные и содержательные вопросы по конкретному примеру. Подготовьте ответы на эти вопросы, чтобы проверить, достаточно ли они интересны.

Orit Hazzan, James Tomayko. Reflection and Abstraction in Learning Software Engineering?s Human Aspects, IEEE Computer, June 2005. IEEE Computer Society, 2005, All rights reserved. Reprinted with permission.