Содержание сайта
Главная Новичку Цитаты Реализации Статьи Документация
Компании Программы Ссылки Обсуждение Обсуждение 2 Гостевая

Принципы, лежащие в основе Smalltalk-а.

Автор Daniel H. H. Ingalls

Перевод Андрея Собчука, 2003

Эта статья была опубликована в номере журнала "BYTE" посвященном Smalltalk-у в августе 1981 года.

Целью создания Smalltalk-а является желание предоставить компьютерную поддержку творческому началу в любом человеке. Отправными точками для нашей работы являются творческая личность и наисовременнейшая компьютерная техника. Мы решили сосредоточиться на исследовании в двух областях. Во-первых, язык описания (язык программирования), который служит для того, чтобы увязать модель, существующую в воображении человека, с той, которая существует в компьютере. Во-вторых, язык взаимодействия (пользовательский интерфейс), который призван уравнять коммуникационную систему человека с компьютерной. В работе мы следовали циклам, продолжительностью от 2-х до 4-х лет. Этапы каждого цикла соответствуют научным методам:

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

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

Для разминки, я начну с закона, более социального, чем технического. Он во многом несёт ответственность за некоторые черты Smalltalk-а:

Влияние личности: Если система служит духу творчества, то эта система должна быть полностью понятной отдельным личностям.

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

Хороший дизайн: Система должна быть построена с минимальным набором неизменяемых частей; эти части должны быть как можно более общего характера; и все части этой системы должны быть как можно более единообразными.

Язык

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

Рисунок 1 показывает основные компоненты, которые мы обсуждаем в нашей дискуссии. Модель человека состоит из тела и разума. Тело содержит основной опыт, и, в контексте нашей дискуссии, является физическим каналом через который мы воспринимаем мир и доносим наши намерения. Опыт сохраняется и перерабатывается в сознании. Творческое мышление (не вдаваясь в механизм его работы) можно представить как спонтанное появление информации в сознании. Язык является ключом к этой информации.

Цель языка: предоставить средство коммуникации.

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

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

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

Рисунок 1:Области рассматриваемые при проектировании языка. Взаимодействие между двумя людьми (или между человеком и компьютером) происходит на двух уровнях. Явные коммуникации включают информацию, передаваемую данным сообщением. Неявные коммуникации включают важные предположения, общие для собеседников.

Взаимодействующие объекты

Сознание человека хранит в себе огромную вселенную различных жизненных опытов, как текущих, так и запомненных. Любой человек может ощутить себя единым со вселенной просто созерцая этот опыт. Но, если он собирается участвовать, буквально стать частью, во вселенной, то ему нужно выявить отличия. Таким образом, можно выявить, что нечто является объектом во вселенной, а всё остальное, соответственно, им не является. Отличия сами по себе -- только начало, но процесс распознавания не становится легче. Каждый раз, когда вы говорите "о том стуле вон там", вы должны повторить весь процесс распознавания этого кресла. Именно на этом этапе у нас появляются ссылки. Мы можем присвоить объекту уникальный идентификатор, и, с этого момента, для ссылки на объект достаточно использования этого идентификатора.

Компьютерная система должна предоставлять модель, которую можно соотнести с моделью в сознании человека. Следовательно:

Объекты: Компьютерный язык должен поддерживать концепцию "объекта" и предоставить стандартную возможность для ссылок на объект в его вселенной.

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

Управление памятью: Что бы действительно быть "объектно-ориентированной", компьютерная система должна предоставлять автоматическое управление памятью.

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

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

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

Так же, как программа приходит в беспорядок при использовании явного управления памятью, так и контроль над системой усложняется если обработка выполняется внешними, по отношению к объекту, средствами. Давайте рассмотрим процесс добавления 5 к некоторому числу. В большинстве компьютерных систем компилятор определяет тип числа и генерирует соответствующий код для добавления 5. Не самый хороший путь для объектно-ориентированной системы, так как точный тип числа нельзя определить на этапе компиляции (подробнее об этом дальше). Возможным решением будет вызов обобщенной процедуры сложения, которая проверяет тип аргументов для определения возможных действий. Это плохое решение, потому что критичная процедура должна редактироваться новичками которые просто хотят поэкспериментировать с собственным классом чисел. Так же, это пример слабого дизайна, так как знания о внутренней структуре объекта размазываются по всей системе.

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

Единообразная метафора: Язык должен быть разработан на основе мощной метафоры которая может быть единообразно применена в любой области.

Примерами успехов в этой области являются LISP, который построен на модели связанных структур, APL на базе массивов, и Smalltalk, который построен на модели взаимодействующих объектов. В каждом случае, большое приложение выглядит так же, как отдельные базовые блоки из которых построена система. Особенно в Smalltalk-е, где взаимодействие между примитивными объектами выглядит так же, как и более высокоуровневое взаимодействие между пользователем и компьютером. Каждый объект в Smalltalk-е, даже скромное целое число, имеет набор сообщений, протокол, который определяет на какие явные сообщения объект может отвечать. Внутри себя, объект может хранить локальную информацию и иметь доступ к разделяемой информации, которая определяет неявный контекст любого общения. Например, сообщение "+ 5" (добавить пять), содержит неявное предположение, что первое слагаемое -- это текущее значение числа, получающего сообщение.

Организация.

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

Модульность: Ни один компонент в сложной системе не должен зависеть от внутренних особенностей другого компонента.

Рисунок 2: Сложность системы. С ростом числа компонентов из которых состоит система, вероятность возникновения незапланированных взаимодействий выростает по экспоненте. По этой причине, компьютерный язык должен быть разработан так, что бы минимизировать вероятность подобных взаимозависимостей.

Этот принцип проиллюстрирован на рисунке 2. Если система состоит из N компонентов, то существует около N в квадрате потенциальных зависимостей между ними. Если предполагается, что компьютерная система будет помогать человеку в решении сложных задач, то она должна минимизировать количество таких зависимостей. Метафора посылки сообщения обеспечивает модульность путём отделения цели сообщения (заключенного в имени) от метода, который используется получателем для достижения цели. Структура данных также защищена, потому что весь доступ к внутреннему состоянию объекта осуществляется через сообщения.

Сложность системы часто можно уменьшить группируя подобные компоненты. В традиционных языках программирования подобная группировка достигается путём типизации данных. В Smalltalk-е для этой цели используются классы. Класс описывает другие объекты -- их внутреннее состояние, протоколы понимаемых сообщений, методы, используемые для ответов на сообщения. Описанные подобным образом объекты называются экземплярами класса. Даже сами классы описываются таким же образом. Они являются экземплярами класса Класс (Class), который описывает протокол и реализацию используемые для описания объектов.

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

Классификация -- это овеществление сути . Другими словами, когда человек видит стул, он осознаёт его как буквально, то есть как "именно эту вещь", так и абстрактно, то есть как "вещь, относящуюся к стульям". Подобная абстракция происходит из удивительной способности разума соединять воедино "подобный" опыт, и эта абстракция проявляет себя как еще один объект в сознании, стул Платона или суть (идея) стула.

Классы являются основным механизмом для расширения в Smalltalk-е. Например, музыкальная система создавалась бы посредством введения новых классов, которые описывают протокол представления и взаимодействия Ноты, Мелодии, Партитуры, Тембра, Музыканта и так далее. Фраза "эквивалентны" из принципа выше имеет важное значение так как гарантирует, что система будет использована так как было задумано. Иначе говоря, мелодию можно реализовать специальной коллекцией Целых, представляющих тон, продолжительность и другие параметры. Но если язык может работать с Нотами так же легко, как и с Целыми, то пользователь естественно опишет мелодию как набор Нот. На каждом этапе проектирования, человек будет выбирать наиболее эффективное представление, допускаемое системой.

Полиморфизм: Программа должна определять только поведение объектов, а не их представление.

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

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

Факторинг (разложение на элементарные составляющие): Каждый независимый компонент системы должен появится только в одном месте.

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

Smalltalk содействует правильной факторизации через наследование. Каждый класс наследует поведение своего суперкласса. Наследование расширяет всё более общие классы, заканчиваясь на классе Объект (Object) который описывает поведение по умолчанию всех объектов в системе. В нашей системе симуляции дорожного движения, Мусоровозка (и все другие классы машин) будет описана, как подкласс общего класса Машина. Как результат, будет унаследовано правильное поведение по умолчанию и получится избежать повторения тех же концепций во многих различных местах. Наследование иллюстрирует дополнительное прагматичное преимущество факторизации:

Принцип рычага: В правильно факторизованной системе, значительная "подъёмная сила" доступна пользователям и разработчикам.

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

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

Виртуальная машина: Спецификация виртуальной машины создаёт основу для применения технологии.

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

Интерфейс с пользователем

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

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

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

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

Операционная система: операционная система -- это всё то, что не влезло в язык. Такого быть не должно.

Вот несколько примеров компонентов обычных операционных систем, которые были внесены в Smalltalk:

  • Управление запоминающим устройством. Полностью автоматическое. Объекты создаются через сообщения к их классам и уничтожаются когда не остаётся ссылок на них. Расширение адресного пространства при использовании виртуальной памяти тоже прозрачно.
  • Файловая система. Включена в стандартную библиотеку с помощью объектов Файлы и Директории с протоколом сообщений, которые поддерживают доступ к файлам.
  • Управление дисплеем. Дисплей -- это просто экземпляр класса Форма, который постоянно видим. Сообщения для графической манипуляции, определённые в этом классе, используются для изменения видимого образа.
  • Ввод с клавиатуры. Устройства ввода тоже смоделированы как объекты, с соответствующими сообщениями для определения текущего состояния или чтения истории как последовательности событий.
  • Доступ к подсистемам. Подсистемы естественным образом включены, как независимые объекты внутри Smalltalk-а: так они могут быть ближе к огромной существующей вселенной описаний, и те, которые вовлечены во взаимодействии с пользователем могут выступать компонентами пользовательского интерфейса.
  • Отладчик. Состояние процессора в Smalltalk-е доступно через экземпляр класса Процесс, который хранит цепочку кадров стека. Отладчик -- это всего лишь Smalltalk-подсистема, которая имеет доступ к состоянию приостановленных процессов. Нужно отметить, что практически единственная ошибка времени выполнения которая может произойти в Smalltalk-е, это сообщение не понимаемое получателем.

Smalltalk не имеет "операционной системы" как таковой. Необходимые примитивные операции, такие как чтение страницы с диска, включены в виде примитивных методов вызываемых в ответ на обычные Smalltalk-овые сообщения.

Будущая работа

Как и можно было ожидать, много чего нужно доделать в Smalltalk-е. Чтобы легче всего понять что именно, нужно постоянно использовать принципы описанные в этой статье. Например, Smalltalk-80 быстро перестаёт справляться с факторизацией, так как поддерживает только одиночное наследование. В будущем, Smalltalk-системы обобщат этот механизм до произвольного (множественного) наследования [Что бы понять, что могло бы получиться см. Self -- Перев.]. Так же, протоколы сообщений не были формализованы. Для указания протокола есть возможность, но согласованность протоколов в разных классах это вопрос стиля. Это легко исправить предоставив соответствующий объект, который можно использовать в нескольких классах. Это позволит типизировать переменные по протоколу без потери преимуществ полиморфизма.

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

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

Естественный отбор: Языки и системы с неизменным дизайном будут вытеснены более лучшими системами.

С каждой секундой, появляется всё лучшая и лучшая поддержка творческому началу. Помощь уже в пути.

Оригинальную статью можно прочитать на сайте Двайта Хьюгза.

Перевод Андрея Собчука, 2003




Есть комментарии? Пишите.