Мою предыдущую статью «История IT. Когда компьютеры были большими…» мы завершили концом 80-х, когда произошло два знаменательных события. Во-первых, появился ООП и объектный язык C++. А во-вторых, появились персоналки, и это принципиально изменило задачи, стоящие перед IT-разработкой.
И дело тут не в том, что появилась возможность держать компьютеры дома, и выполнять на них рабочие задачи: редактировать тексты, вести расчеты, создавать рисунки. Софт для этого принципиально не отличается от аналогичного для больших компьютеров — его умели разрабатывать. Вопрос был лишь в оптимизации и адаптации под ограниченные ресурсы.
Главное изменение в том, что персоналки сделали компьютеры доступными небольшим компаниям. Потребовались системы автоматизации бизнес-процессов, которые сильно отличаются в разных компаниях. Типовую систему сделать сложно: сейчас такие системы уже есть, например, 1C, а в то время их не существовало. Как раз эту задачу помог решить ООП. Эту часть истории развития IT и концепций, которые тогда появились и до сих пор используются, я расскажу в этой статье.
Появление ООП
Прежде чем рассказывать, как ООП решил задачу разработки бизнес-приложений надо поговорить про объектно-ориентированный подход (ООП) как таковой.
Для начала посмотрим историю. Я знаю про мнение, что ООП возник в конце 1960-х. В частности, так говорит вики: элементы есть в Алголе (1960), в 1967 скандинавы сделали язык Симула с замечательными концептами, но не слишком хорошей реализацией, а в 1972 появился Smalltalk. Но я полагаю, что с современной точки зрения это не важно: в Алголе объектов в современном смысле точно не было, Симула не взлетела, а Smaltalk реализует акторную модель, которая существенно отличается от ООП.
В чем отличие акторной модели? Объекты активны и обмениваются между собой сообщениями. Это самостоятельный способ моделирования мира, хотя на некотором уровне абстракции это частный случай объектов ООП. Однако, поскольку эффективная реализация такого подхода была затруднена, то концепты тогда не получили распространения. Только сейчас (2010-е) это набирает популярность: акторная модель Erlang, реактивное программирование и ряд других концептов. Но при этом широкие круги разработчиков про Smaltalk уже совсем не в курсе. Хотя авторы С++, конечно, про этот язык знали и опирались на него, так же как на Симулу и Алгол.
У разных гуру, как обычно, разные мнения. Разработчики объектных языков говорят о принципиальных новшествах, для реализации которых они сделали свои языки. Это Бьерн Страуструп, разрабатывавший в 1979-1986 первый вариант языка C++. Практически параллельно с ним работал Бред Кокс, автор Objective-C (1982), Бертран Майер, разработавший Eiffel (1985) с концепцией design by contract, и другие.
Однако, рассказывая историю языков, статьи вики всячески подчеркивают, что это были не оригинальные идеи, они уже были в ранее разработанных языках, и авторы концептов не просто были с ними знакомы, а использовали эти языки. Этого же мнения придерживаются некоторые гуру, разрабатывавшие структурное программирование. Например, Николаус Вирт, работавший над Алголом, а позднее разработавший Паскаль. Он полагает, что в Алголе объекты «почти были», а С++ и другие объектные языки ничего принципиально нового они не принесли.
Ситуация типична для любого новаторства в искусстве или технике: автор знает, что именно нового он внес, в чем были его инсайты в процессе создания и какие проблемы были решены. А гуру прежних поколений и наблюдатели со стороны склонны занижать и обесценивать новаторство, объясняя, что всё это уже известно. И сейчас любой IT-шник может это наблюдать в обсуждении новых языков, фреймворков, сред работы или даже новых таск-трекеров и досок.
Хор голосов «это лишь очередная реализация давно известного и потому она не стоит особого внимания» звучит постоянно и громко. Особенно громко по поводу тех языков, фреймворков, или инструментов, которые становятся популярными. Люди реально не хотят разбираться, что именно нового появилось. А оно определенно появилось, иначе бы это средство не получило популярность. Все-таки, программисты – люди прагматичные, и им важно, чтобы инструменты реально давали новые возможности, а не просто были модными. И то, что авторы не всегда понимают, в чем суть принесенных новшеств и преимуществ, не отменяет их значения. В общем, это – старая история, ее характерный пример связан с популярностью языка C, взлетевшего вместо «правильных» Алгола и Паскаля.
Таким образом, я полагаю, что в 1976 году Николаус Вирт своей книгой «Алгоритмы + Структуры данных = Программы» завершил предыдущую эпоху структурного программирования. А появившийся в начале 1980-х С++, позволивший прозрачное отражение этой парадигмы в коде, открыл эпоху ООП.
Понятно, что объекты можно делать даже на ассемблере и уж тем более на любом процедурном языке высокого уровня, но поддержка их на уровне языка сильно облегчает задачу. И именно С++ дал развитые механизмы наследования типов и виртуальных функций, порождать более сложные типы на основе простых, усложнять поведение, и по-разному комбинировать типы объектов при создании новых. Поэтому предыдущее развитие, включая язык Симула, я полагаю предысторией, концепты которой были взяты в С++, но существенно дополнены, в частности, инкапсуляцией сложности внутри объекта. Равно как и концепты структурного программирования, которые мы продолжаем использовать при реализации методов объектов, обеспечивая понятность программного кода.
Поговорим об объектах…
Итак, в C++ появились объекты. Объект — это объединение данных и алгоритмов их обработки с инкапсуляцией сложности внутри. Появляется наследование, полиморфизм, абстрагирование как концепты порождения более сложных объектов на основе простых.
Как обычно, набор концептов разный у разных методологов, с разным уровнем удаления в теорию от практики. Один из самых известных наборов концептов – принципы SOLID. Что тут интересно. Принципы SOLID говорят о том, что как бы вы не расширяли поведение базового класса при его наследовании, у вас не должно быть возможности изменить функционал базового класса. То есть, если правки вносили только в класс-наследник, например, Заказ с доставкой
, то бизнес-логику базового класса Заказ
можно не проверять, она гарантированно работает. Любой разработчик-практик знает, что это не так, что при доработке классов-наследников тестировании логики базового класса необходимо, потому что бывают тонкие эффекты. То есть практически этот набор принципов не выполняется.
Почему так происходит? А потому что возможность изменить поведение базового класса в некоторых частных случаях практически необходима, и потому во всех языках есть те или иные способы это сделать, чтобы обеспечить скорость разработки.
Но вот с точки зрения развития больших систем возможность наложить такие ограничения на код, чтобы изменения в рамках одного сценария гарантированно не повлияли на другие – очень заманчиво. В том числе, кстати, и с точки зрения стоимости разработки. Можно привлекать не слишком опытных программистов, не способных удержать в голове проект целиком, но способных разобраться с реализацией не слишком большого законченного фрагмента, который, к тому же, можно хорошо протестировать.
Но это – непростая задача, даже если не смотреть на объекты. Например, для этого следует запретить использовать в коде if
для ветвления по сценариям, ведь вписывая новый else if
в произвольном месте вы потенциально влияете на все последующие блоки. Вместо этого следует везде использовать switch
, с заходом только в одну ветку кода и без взаимного влияния условий, при этом в default
можно писать лишь реакцию на ошибки. Нельзя сказать, чтобы так было писать невозможно, я слышал о проектах, в которых создавали платформу именно для такой разработки, и в результате junior-разработчики успешно делали устойчиво работающие сложные проекты. Но это – очень непривычно, особенно для состоявшегося разработчика.
Два ООП: Объектно-Ориентированное Программирование и Проектирование
Итак, началась эпоха объектно-ориентированного программирования. Объекты появились в языках и быстро завоевали популярность. И программисты начали использовать их для разработки собственных библиотек – для работы с интерфейсными формами, таблицами базы данных и многими другими внутренними объектами своих программ. При этом от библиотечных объектов можно было наследоваться, дополнять их атрибутами и методами, а также влиять на их поведение в точках расширения через виртуальные функции и другие механизмы.
Но это напрямую не решало задачу массовой разработки сложных бизнес-приложений. И в 1990-е тут был сделан следующий шаг. Появилось Объектно-ориентированное проектирование. По-русски это тоже ООП и это вносит путаницу, а по-английски названия отличаются: Object-oriented programming и Object-oriented analysis and design.
Вехой является появление и развитием UML (Unified Modelling Language), разработку подхода вели Ивар Якобсон, Гради Буч, Мартин Фаулер и ряд других авторов. Здесь есть своя интересная история. Многие гуру программирования, как это обычно бывает, предпочитали не сотрудничать с другими с порождением общих концептов, разрабатывали собственные подходы и графические нотации. Я слышал даже анекдот, который рассказчик относил именно в те времена:
– Чем отличатся методолог от террориста?
– С террористом можно вести переговоры.
Но в середине 1990-х компании Rational Software получилось собрать троих сильных методологов – Гради Буча, Джеймса Рамбо и Ивара Якобсона, и поставить перед ними задачу создания единого методологического подхода со своим языком. И они были вынуждены договариваться.
Так появился UML. Результат оказался столь удачной, что другие производители забеспокоились, как бы такой продукт не оказался во власти монополиста – и был организован консорциум Object Management Group (OMG), который до сих пор является независимой площадкой согласования различных стандартов.
И особо следует отметить роль Мартина Фаулера как популяризатора этих подходов. Его книга 1997 года UML Distilled, представила UML тяжелый язык, в котором диаграммы были лишь частью, как средство легкого эскизного проектирования и принесла ему популярность.
С UML есть интересный парадокс: хотя его замысливали как язык моделирования, он практически не получил распространения в этом качестве. Зато получили распространение его диаграммы, которые там более десятка видов. По сути, произошло второе рождение диаграмм как средства программирования и составной части языков, после блок-схем, которые были в самом начале (1960-е) и служили больше для обучения (сложные алгоритмы на них были нечитаемыми) и ER-диаграмм, использовавшихся для представления структур реляционных баз данных.
Потребности проектирования бизнес-приложений
До появления персоналок компьютеры были доступны только большим компаниям и корпорациям. А их бизнес-процессы являются специфичными, не похожими друг на друга, даже если используются общие методики. И это связано с масштабом деятельности.
Дело в том, что в малом и среднем бизнесе довольно много обеспечивается средствами взаимной коммуникации сотрудников, которые знают друг друга, и именно на этом уровне решается обработка всех особых сценариев и инцидентов. В информационную систему достаточно заложить лишь 90-95% типовых сценариев – остальное можно «донести на руках».
Если у вас в день проходит 100 заказов, то с 5-10 особыми случаями разберется один человек. Если в день идет 10000 заказов, то особых случаев становится 500-1000, одному человеку с этим точно не разобраться. А если этим занимается группа из 50 людей, то им уже нужна автоматизация для координации деятельности. Кроме того, у них часто возникает специализация по отдельным видам особых случаев, передача их и так далее, то есть появляются свои ветви бизнес-процессов. Именно с этим связана специфика бизнес-процессов больших компаний. И именно поэтому для них не подходят типовые системы. А при внедрении таких систем, как SAP, которые ориентированы именно на большие компании, возникает бесконечная кастомизация.
Впрочем, для мелких и средних компаний возможность кастомизации и наличие точек расширения, заложенных в приложение, тоже важно. Потому что у любой успешной компании есть свое know-how, которые она отличается от аналогичных компаний на рынке, и которое обеспечивает успех в ее собственном сегменте. И если это know-how лежит в области, покрытой автоматизацией, то оно так или иначе должно быть отраженно в информационной системе. Успех 1C связан именно с тем, что необходимость кастомизации была понятна с самого начала, и компания ориентировалась на то, что ее будут делать не специалисты самой компании-разработчика, а местные разработчики, работающие рядом с предприятием-заказчиком. Ведь понять специфику бизнеса на расстоянии – очень трудно, необходима живая коммуникация. А просторы нашей родины не позволяют это делать централизовано.
Тем более тогда, в 90-х – интернет был намного слабее современного. Я помню, что одним из наших заказчиков был Липецккомбанк. Мы начинали работу с московским филиалом, но потом делали АБС для всего банка, у которого в Липецкой области было несколько районных отделений. И связь между отделениями считалась очень приличной по тем временам – 64к бит, максимум, что дает выделенный телефонный провод: если арендовать его на год, то телефонисты физически соединяли разные сегменты на телефонных подстанциях, и была хорошая связь. А вот с Москвой арендовать прямой провод было невозможно, их было очень мало, и вся Липецкая область сидела на канале 128к бит из двух проводов.
Проектирование бизнес-приложений в ООП
Объектно-ориентированное проектирование основано на том, что разрабатывая модель приложения, мы отталкиваемся от модели бизнес-области, для создания которой тоже применяем методы ООП. Мы не просто выделяем словарь понятий, а строим онтологическую модель из объектов, обладающих определенным поведением, атрибутами и связями между собой, и взаимодействующих в процессе деятельности.
При этом UML, позволил использовать средства и нотации, ориентированные на разработку софта, для разработки этой модели. Диаграмма активности для описания бизнес-процессов, диаграмма классов для описания объектной онтологии предметной области, диаграмма состояний для описания поведения отдельных объектов, диаграммы коммуникации и синхронизации для описания взаимодействия разных субъектов в процессе деятельности.
И при этом для моделирования предметной области можно использовать наследование и другие абстракции, которые проработаны в объектно-ориентированных языках для объектов в коде. А это – весьма мощный аппарат.
Правда, тут надо отметить одну опасность. Модель предметной области необходимо верифицировать с Заказчиком, с представителями бизнеса и пользователями. А они обычно не владеют ООП в том объеме, в котором его понимают разработчики-архитекторы, и который заложен в нотацию UML во всей полноте. А значит, надо использовать в диаграммах не полную мощность, а интуитивно-понимаемое подмножество.
При этом есть определенная опасность. Например, вы твердо знаете, чем отличается агрегация от композиции, а объект от интерфейса, используете их в диаграммах по назначению. И рассчитываете на то, что читатель диаграммы тоже это знает, а если не знает – то обратит внимание на различающиеся значки, разберется – и поправит, если вы ошиблись. Так вот, скорее всего, он – не спросит. Он подумает, что это – какая-то особенность, которая зачем-то нужна программистам, а ему – не интересна. Поэтому все такие вещи надо проговаривать явно словами и верифицировать, если вы сомневаетесь в типах отношений между объектами. То же относится и к другим диаграммам, например, к линейке синхронизации на диаграмме активности, тем более, что ее трактовку меняли в ходе развития UML.
Объектный и процедурный подход: в чем разница?
Тут уместно привести конкретный пример, чтобы показать разницу между ООП и проектированием в предшествующую эпоху структурного программирования. Я это покажу на примере интернет-магазина, потому что вы все знаете, что это такое. Но вы представьте, что речь идет о 90-х, когда сайты только-только появлялись и кому-то из тех, кто до этого торговал, рассылая по почте бумажные каталоги и принимая заказы, с бумажным документооборотом, пришла в голову идея использовать для представления товаров и получения заказов сайты в интернете. И вы выясняете, что же вам предстоит реализовать в системе, не зная про процесс.
Понятно, что знакомство начинается с выделения понятий, составления словаря предметной области, а так же бизнес-процессов. В данном случае будут каталог товаров, покупатели, их заказы с позициями из каталога, адреса доставки, сотрудники склада, которые должны собрать заказы по заданиям, и курьеры, которые их доставят. Эти и другие понятия будут зафиксированы в словаре. Будут выделены объекты, которые хранятся в информационной системе – товары, заказы со строками, пользователи системы со своими ролями и действиями, которые они выполняют. А вот дальше будет существенная разница.
В процедурном подходе будет такт проектирования структур данных, на котором с объекты будут в таблицы базы данных с некоторым набором полей. Отражаться на пользовательском интерфейсе они так же будут в виде таблиц или форм для индивидуальной работы с записью. В интернет-магазине будут таблицы товаров, заказов, их строк, курьеров и покупателей, если информация о них должна жить дольше одного заказа.
Следующим тактом будет проектирование алгоритмов обработки данных, реализуемых в виде отдельных процедур, доступных с интерфейса по кнопкам или другим образом и обеспечивающим выполнение необходимых действий. Например, как оплата заказа, назначение курьера или фиксация подготовки заказа на складе.
Если же мы работаем в объектном подходе, то после словаря предметной области мы должны сделать следующий такт – построить для предметной области объектную онтологию. То есть выделить типы объектов, которые определяют поведение отдельных экземпляров объектов, набор атрибутов, отражающих информационное содержание объекта и его связь с объектами других типов. Такое описание – часть философской традиции построения картин мира. Хотя конкретных имен и источников я тут не назову, не специалист.
На мой взгляд, те, кто придумывали объектные языки программирования, по сути, черпали из тех же источников, просто опосредовано и не за один такт, этот процесс как раз был начат Алголом и Симулой, продолжен в C++ и развивается дальше. Авторы новых концептов и языков сейчас больше опираются на предшествующие идеи в IT, чем на философские концепции, но первоисточники – все-таки в философии.
Интересно, что в мир бизнеса, да и в целом в образование, все эти идеи и концепции сейчас распространяются именно из IT, а не из философии. При этом в значительно более богатом и формализованном варианте, который они получили в IT.
При объектном проектировании в предметной области появятся объекты Заказ, Покупатель, Товар, Курьер, которые будут хранить свои данные и методы, и напрямую манипулировать данными объектов нельзя, можно работать только через его методы. Например, у Заказа будут методы "Добавить товар", "Оплатить", "Назначить курьера" и так далее.
Если у вас есть два вида доставки — самовывозом и курьером, то в первом случае таблица заказов будет содержать все необходимые поля (для курьера нужна карта и другие детали), а описании алгоритмов обработки вы будете указывать, с какими именно заказами эти алгоритмы должны работать, какие для них есть особенности.
В объектном же подходе, скорее всего, будет выделен базовый объект Заказ, включающий общее поведение и хранение данных, и два его наследника — "Заказ с самовывозом" и "Заказ с доставкой" со своими дополнительными методами, а также с какой-то дополнительной логикой в базовом поведении. Например, курьер не может принимать оплату картой, а принятую оплату наличными он еще должен сдать кассиру, и это изменяет логику метода "Принять оплату", который есть в базовом классе "Заказ".
От проектирования к реализации
Если мы посмотрим на реализацию таких систем, как SAP или 1C, а также на связанные с ними документацию и постановки, то легко заметим, что они написаны не в объектном, а в процедурном подходе. Описание ведется в терминах таблиц и алгоритмах. И это – не случайно, в первой половине 90-х, когда эти системы еще зарождались, объектно-ориентированное проектирование тоже лишь начинало свое развитие.
И даже после появления шаблона «Модель предметной области», такой подход к реализации не стал популярным. Шаблон говорил, что объекты в программе должны отражать объекты, которые есть в реальном мире и которые мы зафиксировали в модели предметной области. Однако, объекты хранились в реляционной базе данных в виде таблиц, потому что именно они обеспечивали эффективную работу с большими объемами данных, и это ограничивало возможности реализации.
Здесь тоже стоит отметить Мартина Фаулера и его книгу «Patterns of Enterprise Application Architecture» (в переводе – Шаблоны корпоративных приложений и Архитектура корпоративных программных приложений), посвященную шаблонам разработки. О модели предметной области Фаулер пишет, что она – довольно сложна и потому ее не следует использовать для простых приложений. И рекомендует использовать гораздо более простые шаблоны, такие как Record Set или Transaction Script.
При этом сложность связана не только с реализацией по модели, сколько со сложностью освоения, то есть перестройки своих навыков проектирования приложения. И, говоря о себе, пишет, что освоил и оценил ее не сразу, а лишь столкнувшись с действительно сложными приложениями. В этом случае принципы инкапсуляции сложности внутри объекта и развитые средства абстракции, заложенные в модель, дают существенное преимущество.
Однако, успешно освоив модель, он даже простые приложения делает с ее использованием, потому что они получаются проще и изящнее, чем без нее. И в них оказывается заложен больший потенциал развития за счет инкапсуляции сложности в объектах и возможностей, связанных с точками расширения. А это важно для большинства приложений.
Реализация Модели предметной области в коде
В чем же состоят проблемы реализации? Объекты предметной области хранятся в таблицах реляционных СУБД. Так было вплоть до начала 2010-х, когда развитие public web, обеспеченное развитием технологий связи и массовым высокопроизводительным интернетом привело к разработке высокопроизводительных NoSQL баз данных, обеспечивающих требуемую производительность. И они получили широкую популярность. Впрочем, сейчас реляционные базы данных наверстывают упущенное, и возможности PostgreSQL по хранению и обработке объектных данных становятся сопоставимы с NoSQL БД, а к самим NoSQL базам данных пишут реляционные адаптеры, обеспечивающие выполнение SQL-запросов. Таким образом, вслед за мультипарадигмальными языками программирования появляются гибридные, мультипарадигмальные базы данных.
Таким образом, если мы хотим работать на сервере приложений, написанном на объектном языке разработки, с объектами предметной области, нам необходимо сначала преобразовать их из реляционного представления базы данных в объектное для сервера приложений, а после завершения работы – провести обратное преобразование. Для этого сейчас используют специальный класс софта – ORM, Object Relational Mapper. А в 90-е и первую половину нулевых это надо было обеспечивать самостоятельно при разработке приложения. При этом, используя такое преобразование, мы теряем возможности массовой работы с записями в таблице, которые представляла реляционная парадигма. А часть бизнес-данных, например, данные учета и подготовка отчетов, очень плохо отражаются в виде отдельных объектов. Именно поэтому применение модели предметной области было ограниченным.
Совместное использование в языках программирования объектной и реляционной парадигмы появилось только в версии C# 2008 года, при чем для этого пришлось включить в язык еще и функциональную парадигму с ее ленивыми вычислениями. В результате стало возможным применять реляционные операторы построения запросов к коллекциям объектов.
Отметим, что перспективы, которые открывает совместное использование этих парадигм в одном языке методологами подходов к программированию не осознано до сих пор. Теорий, книг и других материалов, соразмерных паттернам объектного программирования до сих пор не появилось. Практическое использование широко развито, а теоретики больше сосредоточены на том, как конкретные приемы нарушают те или иные теоретические положения и к каким побочным эффектам они могут привезти. То есть мы имеем дело с типичным, периодом, когда старые теории уже не работают, а новые – пока не созданы, похоже, над их созданием никто не работает. А ведь сейчас требуется не просто объединить эти парадигмы, но и включить акторную модель, основанное на обмене сообщениями, реактивное программирование и другие современные подходы.
Впрочем, я могу ошибаться, и потому у меня просьба к читателям статьи: если вы знаете современные шаблоны и теоретические подходы, основанные на совместном использовании многих парадигм, напишите мне в комментариях.
Мой опыт: ORM внутри СУБД
Тут я хочу рассказать, что и ООП и модель предметной области можно использовать на самых разных платформах. В начале 2000-х мы в компании выбирали технологический стек для разработки большой серии проектов. И нам очень нравилась идея двухзвенной архитектуры с тонким клиентом, инкапсулирующим бизнес-логику на сервере базы данных. Это позволяло обрабатывать в бизнес-логике больших объемов данных, что было проблематично на сервере приложений, обеспечивало стабильность клиентского приложения и ряд других преимуществ.
Вообще идеальным клиентом был бы web-интерфейс, но тогда он не годился для enterprise-приложений – работа в интерфейсе с таблицами, содержащими тысячи строк, была принципиально невозможна, и уровень интерактива, которые тогда обеспечивал web, был весьма низок и не шел в сравнение с десктоп-клиентами. Поэтому клиентское приложение мы писали сами на .Net, который тогда как раз появился и показался нам более перспективным, чем Delhi и Java- стек для десктопа.
По базам данных тогда не было значимой альтернативы, помимо Oracle, а его PL/SQL был достаточно подходящим для реализации процедур. И в принципе схема получалась вполне рабочей. Но при этом мы разрабатывали сложные корпоративные приложения, и очень хотелось использовать модель предметной области, чтобы получить преимущества ООП. И мы приняли решение написать свою небольшую объектную платформу внутри Oracle, в которых метаданные описывали бы объекты предметной области с атрибутами, методами и наследованием. Код конкретных методов при этом реализовывался на PL/SQL, но процедуры платформы реализовывали бы обобщенную работу с объектами, и в нужных местах была бы возможность писать с их помощью обобщенные интерфейсы. Я был главным архитектором и одним из ведущих разработчиков.
В целом затея оказалась вполне успешной. Метаданные описывали типы объектов и их наследование с маппингом на таблицы хранения. Ядро получилось полностью рефлексивным: метаданные были описаны как объекты ядра, и их можно было редактировать через обобщенные процедуры. А еще у нас получилось сделать не ограничиваться объектной парадигмой: реляционная парадигма так же была встроена, был собственный аналог linq, конструирующий запросы на основе объектных метаданных.
Разработка начата в 2003 на основе имеющихся наработок, первая версия ядра была написана в том же году силами несколькими разработчиками одновременно с использованием этого ядра как платформы для разработки бизнес-приложений. И далее оно успешно развивалось и использовалось как платформа разработки. И используется до сих пор, ряд приложений, написанных в нулевые, не просто эксплуатируются до сих пор, а успешно развиваются в темпе развития бизнеса.
Domain Driven Design
Дальнейшее развитие ООП в виде модели предметной области получил в виде Domain Driven Design (DDD), основанного на одноименной книге Эрика Эванса. Книга была написана в 2003, но на русский была переведена только в 2010 под названием «Предметно-ориентированное проектирование». А в 2006 была написана книга Джимми Нильссона «Применение DDD и шаблонов проектирования», переведенная почти сразу, в 2007. Но Нильссон сосредотачивается на практическом использовании, а не на концептах, поэтому из его книги было совсем не очевидно, что нового DDD добавляет к давно известному подходу проектирования и разработки на основе модели предметной области.
Единый язык и единая модель
Какие же принципиальные дополнения внес Эрик Эванс? Во-первых, он сделал следующий логический шаг в части модели. Он сказал, что раз уж модель предметной области является основой кода приложения, то она должна быть понятна как бизнесу, так и разработчикам, и всем остальным участникам проекта. И простого словаря предметной области для этого не достаточно: во-первых, он не включает в себя понятия реализации, а во-вторых, толкования слов недостаточно. Поэтому в проекте необходимо выработать Единый язык, (Ubiquitous Language), который был бы понятен всем участников проекта и на котором уже описывается модель предметной области и системы. По сути, единый язык представляет собой рабочую онтику проекта.
Отметим, что до этого предполагалось, что модель предметной области делает бизнес-аналитик на языке бизнеса, а затем системный аналитик или архитектор на основе этой модели ведет проектирование системы, описываемой техническими терминами, понятными разработчикам. При этом разработчики и другие технические специалисты не обязаны понимать модель предметной области и ее язык и наоборот, бизнес-аналитики, представители бизнеса и пользователи не обязаны разбираться в техническом языке описания системы.
Таким образом, мы имели две модели, описанные на разных языках, с узким кругом специалистов, которые разбираются в обеих. Все это неплохо, когда модели стабильны, и их создание происходит однократно. Но бизнес непрерывно развивается, в том числе в процессе разработки системы, и потому обе модели непрерывно развиваются, надо поддерживать соответствие и целостность. И потому с таким подходом возникают проблемы, как в inhouse-разработке, приближенной к бизнесу, так и при итеративной Agile-разработке и вообще при любой разработке с короткими циклами. Возникает сложная задача перевода между разными моделями, написанными на разных языках, удержание их целостности и взаимной согласованности. Agile пытался решить эту проблему, вообще отказавшись от моделей, или хотя бы от модели предметной области. Но для сложных проектов это не подходит.
DDD смотрит на это иначе. Он говорит, что нужна единая модель, понятная всем участникам проекта. И потому написанная на языке предметной области: ведь разработчиков много меньше, чем бизнес-специалистов и пользователей, и им проще освоить их язык, чем наоборот. А для того, чтобы у них не было необходимости изучать предметную область целиком, необходимо сделать единый язык проекта, который включает не все описание предметной области, а только часть, необходимую в рамках данного проекта разработки, и пользоваться именно им.
Единая модель в ходе проекта сначала появляется как модель предметной области, но постепенно становится моделью системы, которая в этой предметной области работает и решает конкретные задачи.
Это изменение можно представить на следующей схеме.
Отметим, однако, что DDD и модель предметной области так и не завоевала большой популярности в корпоративном мире. Этому есть несколько причин. Во-первых, легаси-системы, такие как SAP, 1С и множество других архитектурно разработаны еще до появления объектно-ориентированного проектирования, модели предметной области и DDD. Зато они хорошо ложатся на традиционные шаблоны, описанные еще Виртом и широко вошедшие в образование. Консерватизм традиционного образования является второй причиной. А третья связана со сложившимся разделением труда, делением на бизнес-аналитиков, занимающихся процессами, системных аналитиков, занимающихся проектированием и разработчиков, которые не особо думают про бизнес. Конечно, это негативно сказывается на конечном результате, вновь и вновь воспроизводя старый мем о создании систем с картинки. Но в моменте ведь это очень удобно, а, главное, зафиксировано во всех стандартах, что представляет собой четвертую причину.
Ограниченный контекст
Мы подходим ко второму, и самому важному новшеству, которое внес Эрик Эванс – понятию ограниченного контекста (bounded context). Было признано, что построение единого языка для большой предметной области является сложной и не реалистичной задачей. Поэтому предлагается поделить область на ограниченные контексты, в каждом из которых язык строить независимо, а на границах сопрягать языки между собой разными способами, и держать общую карту этих понятий (context map).
Но при этом, поскольку область одна, то в контекстах получается много пересекающихся понятий. И Эванс предложил использовать для них весь аппарат, накопленный ООП для объектов — наследование, полиморфизм, или наоборот изоляция и трансляция. Варианты взаимодействия показаны на схеме из книги Эванса. Это реально круто, потому что снимает проблемные холивары о «правильных» системах понятий, которые возникали между специалистами, редко взаимодействующими между собой в деятельности. По сути, это распространение на построение онтологий тех подходов ООП, которые применялись для построения отдельных объектов.
Следует отметить, что ограниченные контексты в книге Эванса были описаны почти в конце, в четвертой части «Стратегическое проектирование». И добирались до них далеко не все, это новшество не было оценено в полной мере. Поэтому когда Вон Вернон писал свою книгу по DDD «Реализация методов предметно-ориентированного проектирования», он вынес эти концепции в начало книги. Об ограниченных контекстах у меня был отдельный доклад на WIAD-2019 «От монолитных моделей предметной области — к модульным».
Не объектные модели предметной области
Я познакомился с DDD после выхода книги Эрика Эванса на русском, и сразу оценил близость подхода к тому, что мы делаем в разработке и проектировании. И первые доклады у меня были весной 2011 года на AgileDays «Модель системы — архитектура для Agile-разработки» и Application Developers Days «Необъектные модели предметной области. Опыт CUSTIS».
Для меня особенно важно было то, что Эванс не ограничивается объектными моделями предметной области, а пишет, что этот подход можно применять для любых моделей. А примеры объектных моделей с шаблоном Rich Object он приводит потому, что для них отражение оказывается проще за счет использования объектных языков программирования. Дело в том, что в наших приложениях всегда была большая учетная часть, которая плохо представляется именно в виде объектной модели. И это вызывало определенную неудовлетворенность и сомнения. DDD-подход показал мне, как с этим правильно работать.
Отметим, что вопросы использования модели предметной области и прозрачность ее отражения в код актуальны и сейчас. Архитектура приложений уходит от монолитов, в центре которых находится модель предметной области, к микросервисной архитектуре и многослойным моделям. И тут по-прежнему актуален тезис о том, DDD вовсе не требует применения Rich Object. Вы можете применять анемичную доменную модель, основанную на транспортных объектах, писать бизнес-логику в отдельных контроллерах на сервере приложений и клиенте, использовать другие приемы. Важно, однако, чтобы отражение в код для всех моделей предметной области выполнялось единообразно. Я назвал такой единообразный способ отражения «технологическими рельсами», когда готовил доклад «DDD: проблемы и решения в отражении модели предметной области в код» для Software People-2013, была в прошлом такая хорошая конференция.
В целом по теме Domain Driven Design у меня накоплено много материала, которые послужили основой многих докладов. Последний был в феврале на WIAD-2020 «Domain-driven design: от справочников и документов до отчетов». Но в один доклад материал точно не помещается. Думаю, он ляжет в основу будущих статей.
А я на этом завершаю рассказ про ООП и Персоналки. Следующий этап развития IT связан с технологиями public web, которые не только стали ведущими в интернет-мире, но превзошли традиционные технологии по производительности и надежности и успешно вытесняют их из области enterprise-разработки. А сейчас начинается еще один, связанный с развитием нейронных сетей и других технологий ИИ.
Но пока я знаком с ними не слишком глубоко, чтобы писать их историю. Хотя и не совсем чужд. У меня недавно был забавный опыт прототипирования для одной задачи в виде бессерверного автономного приложения в браузере на Java Script. Результат оказался столь удачным, что заказчик решил пожить с ним в боевом режиме, не делая серверный вариант. Так что поживем – увидим.
richman5
ТЛ; ДР хотя тема и интересная…
MaximTsepkov Автор
Что делать… Был вариант побить это на 2-4 части, но, на мой взгляд, тогда бы пострадала целостность восприятия…
richman5
Да, каждая часть интересна сама по себе, и хотелось бы видеть еще и выводы, или другими словами — предсказания, куда будет двигаться инженерная мысль в этих сферах: ОО-ЯП, DDD,… Думаю, что вам это под силу )
MaximTsepkov Автор
Это — непростые темы. Про языки программирования, как я писал в статье C# 2008 с linq открыл мультипарадигмальные конструкции, когда мы имеем одновременно объектную, функциональную и реляционную парадигму. И дальше практики такие композитные штуки развивают, насколько я понимаю. В Kotlin элементы этого вроде есть (хотя я глубоко не копал), JavaScript элементы таких конструкций включает… А шаблонов программирования и теоретических подходов к совмещению парадигм — не появилось. И вряд ли я тут что-то смогу написать, я не теоретик подходов к программированию.
С DDD еще интереснее, и я тоже отчасти писал. Классические объекты более-менее соответствуют структуре Enterprise-монолиты, а не микросервисы и агентов, обменивающихся сообщениями. Микросервисную и мультиагентную архитектуру надо проектировать по-другому. У меня есть мысли на этот счет, на AnalystDays буду делать об этом доклад — посмотрим, насколько получится системно изложить… Если хорошо — напишу статью.