1.1 Концептуальные модели
В большинстве книг по объектному моделированию рассуждается об анализе и проектировании. При этом практически нет единого понимания, где проходит граница между этими двумя видами деятельности. Важным принципом объектной разработки является проектирование программного обеспечения таким образом, чтобы его структура отражала суть проблемы. Одним из результатов применения принципа является то, что модели, созданные в результате анализа и проектирования, в конечном итоге оказываются заведомо похожими, это заставляет многих людей думать, что между ними нет никакой разницы.
Я считаю, что разница между анализом и проектированием все же существует, но она все чаще переходит в разряд нюансов. При анализе вы пытаетесь осознать проблему. На мой взгляд, это не просто перечисление требований в сценариях использования [8]. Use-cases — ценная, если не основная, часть разработки системы, но их получение — не конец анализа. Анализ также включает в себя попытку заглянуть за формальное определение требований, чтобы составить ментальную модель того, что происходит в проблеме.
Представьте, что кто-то хочет написать программное обеспечение для симуляции игры в снукер. Эта проблема может быть оценена в терминах сценариев использования, которые описывают поверхностные характеристики: «Игрок ударяет по белому шару так, что он летит с определенной скоростью; он ударяет по красному шару под определенным углом, и красный шар проходит определенное расстояние и направление». Вы могли бы описать несколько сотен подобных случаев и измерить скорости мячей, углы, пройденные расстояния. Но одних этих примеров будет недостаточно, чтобы написать хорошую симуляцию. Чтобы хорошо справиться с задачей, нужно заглянуть глубже и понять законы движения, связывающие массу, скорость, импульс и тому подобное. Понимание этих законов значительно облегчит понимание того, как можно построить программное обеспечение.
Проблема с шарами для снукера необычна тем, что законы физики для такого моделирования хорошо и давно известны. Для многих предприятий такие законы не так хорошо изучены, и нам приходится прилагать усилия, чтобы их раскрыть. Для этого мы создаем концептуальную модель — мысленную модель, которая позволяет нам понять и упростить проблему. Создание концептуальной модели — необходимая часть разработки программного обеспечения, и даже самые отвязанные хакеры делают это. Разница заключается лишь в том, рассматриваем ли мы концептуальное моделирование как самостоятельный процесс или как один из аспектов всего процесса разработки программного обеспечения.
Важно помнить, что концептуальная модель — это человеческий артефакт. Законы движения, которые разработчик использует для создания чего-то вроде симулятора снукера, не являются частью реального мира; они представляют собой модель реального мира, модель, созданную человеком. С инженерной точки зрения они эффективны, потому что позволяют нам лучше понять, что происходит в реальном мире. Кроме того, разработчик может использовать более одной модели; для симуляции снукера можно использовать ньютоновскую или эйнштейновскую модель. Можно утверждать, что эйнштейновская модель будет более правильной, потому что она учитывает изменения массы из-за скорости движения шаров и, следовательно, является более точной. Однако разработчик почти наверняка предпочтет ньютоновскую модель, потому что скорости будут настолько малы, что не окажут существенного влияния на симуляцию, но повлекут за собой много дополнительных сложностей. Это иллюстрирует важный принцип: не существует правильной или неправильной модели, есть лишь та, которая более полезна для конкретной задачи.
Выбор модели влияет на гибкость и возможность повторного использования итоговой системы. Вы можете возразить, что разработчику следует использовать эйнштейновскую модель, потому что полученное программное обеспечение будет достаточно гибким для решения проблем, связанных с атомными столкновениями. Но это опасный путь. Слишком большая гибкость системы может сделать ее невероятно сложной, а это уже плохое проектирование. Проектирование требует компромисса между стоимостью создания и поддержкой артефакта и предоставляемыми возможностями. Чтобы создать программное обеспечение, пригодное для конкретной цели, необходимо разработать концептуальную модель, соответствующую потребностям. Вам нужна самая простая модель, какая только может быть. Не добавляйте гибкости, которую вы вряд ли будете использовать.
Самая простая модель — не обязательно первая, которая приходит вам в голову. Поиск простого решения требует много времени и усилий, что может расстраивать. Люди часто реагируют на простую модель, говоря: «О да, это очевидно», и думают: «Так почему же потребовалось так много времени, чтобы придумать ее?» Но простые модели всегда стоят затраченных усилий. Их не только легче реализовывать, но, что еще важнее, их легче поддерживать и расширять в будущем. Вот почему стоит заменять работающее программное обеспечение более простым, но тоже работающим.
Как выразить концептуальную модель? Для многих людей концептуальная модель встроена в их язык программного обеспечения. Преимущество языка в том, что вы можете запустить модель для проверки ее корректности и дальнейшего изучения. Это немаловажное преимущество; я часто использую Smalltalk в своем концептуальном моделировании. Еще одно преимущество заключается в том, что в конечном итоге вам придется перевести модель на язык программирования, поэтому моделирование на целевом языке избавляет от необходимости перевода. (Существуют инструменты, которые могут интерпретировать или компилировать модели анализа и проектирования, тем самым уменьшая проблемы, связанные с переводом).
Опасность использования языка заключается в том, что можно легко запутаться в вопросах его использования и потерять из виду проблему, которую вы пытаетесь понять. (Это меньшая проблема с языками более высокого уровня, такими как Smalltalk. Я знаю нескольких талантливых специалистов по концептуальному моделированию, которые занимаются моделированием на этом языке.) Моделирование на языке программирования также представляет собой опасность привязки моделей к этому языку. Модель может использовать возможности этого языка, которые недоступны в других языках. Это не означает, что концептуальную модель нельзя перенести на другой язык, но это может усложнить процесс.
Чтобы избежать этих проблем, многие используют техники анализа и проектирования для концептуального моделирования. Эти техники помогают людям сосредоточиться на концептуальных вопросах, а не на вопросах проектирования программного обеспечения, и этим техникам легче научить специалистов в данной области. Методы анализа и проектирования используют графические приёмы для большей выразительности. Они могут быть строгими, но не обязательно должны быть таковыми. Методы, предназначенные для реализации кода, должны быть строгими, но когда методы анализа используются в сочетании с языком программирования, они могут быть упрощены.
Одна из основных причин, по которой я использую методы анализа и проектирования, — это привлечение доменных экспертов. Очень важно, чтобы эксперты участвовали в концептуальном моделировании. Я считаю, что эффективные модели могут быть построены только теми, кто действительно понимает затрагиваемую область бизнеса — полноценными работниками в этой области, а не разработчиками программного обеспечения, независимо от того, как долго они работают в этой сфере. Чтобы доменные эксперты занимались концептуальным моделированием, их нужно учить. Я обучал методам объектно-ориентированного анализа и проектирования руководителей служб поддержки клиентов, врачей, медсестер, финансовых трейдеров и корпоративных финансовых аналитиков. Я обнаружил, что ИТ-образование не является ни подспорьем, ни помехой для достижения мастерства в моделировании. Лучший специалист по моделированию, которого я знаю, — врач одной из лондонских больниц. Как профессиональный аналитик и специалист по моделированию, я привношу в процесс ценные навыки: Я могу обеспечить строгость, я знаю, как использовать методы, и мой взгляд со стороны может бросить вызов общепринятой мудрости. Но всего этого недостаточно. Сколько бы я ни работал в сфере вычислений для здравоохранения, я никогда не буду знать о здравоохранении столько же, сколько врач или медсестра. Экспертные знания занимают центральное место в хорошей аналитической модели.
Аналитические методы должны быть независимы от технологии программного обеспечения. В идеале техника концептуального моделирования полностью независима от программных технологий, как и законы движения. Такая независимость не позволит технологиям помешать пониманию проблемы, а полученная модель будет одинаково полезна для всех видов программных технологий. На практике такой чистоты не наблюдается. Я стараюсь разрабатывать очень концептуальные модели, которые полностью сосредоточены на проблеме, но при этом мои методы являются объектно-ориентированными и, следовательно, отражают подход к проектированию программного обеспечения. Вы можете получить хорошее представление о том, как программные технологии влияют на концептуальное моделирование, сравнив модели из этой книги с моделями Дэвида Хэя [7]. Мы оба пытаемся построить концептуальные модели, но наши результаты отличаются, потому что он использует реляционную технику, а я — объектно-ориентированную. Это неизбежный результат природы программного обеспечения. Создание программного обеспечения — это создание виртуальных машин. Языки, на которых мы создаем программное обеспечение, могут как управлять физической машиной, так и выражать потребности проблемы. Одна из причин, по которой наши языки меняются, заключается в том, что мы находим лучшие способы выразить потребности задачи. Таким образом, изменения в языке влияют на то, как мы строим концептуальные модели. Несмотря на несколько сложных моментов (см. главу 14), полученные модели несложно превратить в объектно-ориентированное программное обеспечение.
Однако сейчас я должен сделать одно предостережение: концептуальные модели теснее связаны с программными интерфейсами, нежели с программными реализациями. Одной из важных особенностей объектно-ориентированного программного обеспечения является то, что интерфейс отделяется от реализации. К сожалению, это различие слишком легко потерять на практике, потому что обычные языки не делают явного различия между этими двумя понятиями. Разница между интерфейсом программного компонента (его типом) и его реализацией (его классом) чрезвычайно важна. Многие шаблоны основанные на делегировании из книги «Банды четырех» [6] опираются на это различие, не забывайте о нём при реализации моделей/шаблонов.