Система Orphus

Применение DDD и шаблонов проектирования: проблемно-ориентированное проектирование приложений с примерами на C# и .NET

Автор: Джимми Нильссон
Издательство: Вильямс, 2007
560 страниц
ISBN: 978-5-8459-1296-1
ISBN: 0-321-26820-2

Материал предоставил: Издательство ''Вильямс''
Найти в магазинах
Купить в Books.Ru

Аннотация

Содержание
Отзывы о книге
Об авторе
Предисловия
Вступление: наведение мостов
Назначение книги
Причины для написания книги
Кому адресована книга
Как организована книга
Основания для примеров на C#
Темы, не охваченные в книге
Распределение
Усовершенствованное моделирование
finally{}
Комментарии

Аннотация

Эта книга о разработке корпоративных программных приложений в среде .NET с применением шаблонов проектирования. В ней описаны: проблемно-ориентированные методы проектирования (DDD, или Domain Driven Design), разработка посредством тестирования (TDD, или Test-Driven Development), объектно-реляционное преобразование, т.е. методы, которые многие относят к ключевым технологиям разработки программного обеспечения. По мере развития и усложнения технологии все большее значение приобретают вопросы правильного применения методов проектирования. Ценность этой книги в том и состоит, что она помогает разобраться в этих вопросах. Хотя большинство примеров кода представлено на языке C#, материал книги может оказаться полезным и для тех, кто работает на платформе Java. Книга адресована опытным разработчикам архитектуры и прикладного программного обеспечения уровня предприятий, в том числе и в среде .NET.

Содержание

Отзывы о книге
Об авторе
Предисловия
Вступление: наведение мостов
Благодарности
От издательства

Часть I. Основы

Глава 1. Переоценка ценностей

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

Глава 2. Переход к шаблонам

Вкратце о шаблонах
Предостережения в отношении шаблонов
Шаблоны проектирования
Пример применения шаблона State
Архитектурные шаблоны
Пример применения шаблона Layers
Шаблон Domain Model в качестве другого примера
Шаблоны проектирования для конкретных типов приложений
Пример применения шаблона Query Object
Шаблоны предметной области
Пример применения шаблона Factory
Резюме

Глава 3. РПТ и рефакторинг кода

Разработка посредством тестирования
Порядок выполнения РПТ
Пора приступать к демонстрации
Следствия для проектирования
Недостатки проектирования методом РПТ
Следующая стадия
Заглушки и имитации
Типичный блочный тест
Объявление независимости
Работа с трудными объектами
Замена взаимодействующих объектов тестовыми заглушками
Замена взаимодействующих объектов имитирующими объектами
Последствия для проектирования
Выводы
Дополнительные сведения
Рефакторинг кода
Чистка недоброкачественного кода
Резюме

Часть II. Прикладное ППО

Глава 4. Новая используемая по умолчанию архитектура

Основа новой используемой по умолчанию архитектуры
Смещение акцента с базы данных на модель предметной области
Более конкретный акцент на ППО
Разделение на слои в соответствии с ППО
Первый набросок
Задачи и возможности для примера предметной области
Решение задач по очереди
Модель предметной области на данном этапе
Первая попытка привязать пользовательский интерфейс к модели предметной области
Основная цель
Акцент на простой пользовательский интерфейс
Составление списка заказов клиента
Ввод заказа
Что получается в итоге
Еще одно измерение
Расположение модели предметной области
Изолирование или совместное использование экземпляров
Реализация модели предметной области с сохранением или без сохранения состояния
Полная или частичная реализация модели предметной области
Резюме

Глава 5. Проектирование на основе модели предметной области

Уточнение модели предметной области простым экспериментированием с РПТ
Первая задача: создание классов Order и OrderFactory
Немного логики для предметной области
Вторая задача: создание класса OrderRepository и ввод свойства OrderNumber
Восстановление объекта-сущности из состояния сохраняемости: задание значений извне
Выборка списка заказов
Пора обсудить объекты-сущности
Назад к основному ходу рассуждений
Общая перспектива
Подделка класса OrderRepository
Несколько слов о сохранении
Общая сумма каждого заказа
Сведения о предыстории клиента
Жизненный цикл экземпляра объекта
Тип заказа
Ответственное лицо для заказа
Плавный интерфейс
Резюме

Глава 6. Подготовка к инфраструктуре

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

Глава 7. Порядок устанавливают правила

Разделение правил на категории
Принципы для правил и их применения
Двухсторонняя проверка правил: необязательная (профилактическая) и обязательная (задним числом)
Сохранению подлежат все состояния - даже ошибочные
Правила должны применяться продуктивно
Правила должны допускать поправки для ввода специальных правил
Правила должны размещаться вместе с состоянием
Правила должны быть очень удобными для тестирования
Система должна препятствовать переходу в недействительное состояние
Начало создания интерфейса API
Контекст, контекст и еще раз контекст!
Ограничения, связанные с базой данных
Привязка правил к переходам, связанным с моде
предметной области или же с инфраструктурой
Уточнение принципа ''Сохранению подлежат все состояния - даже ошибочные''
Требования к интерфейсу API для основных правил, связанных с сохраняемостью
Возврат к проблемам интерфейса API
Какая именно проблема возникла
Мы допустили неправильный переход
Если мы забыли выполнить проверку
Акцент на правилах, связанных с предметной областью
Правила, требующие взаимодействия
Поиск методов обработки на основе множеств
Обслуживание проверки достоверности по шаблону Service
Попытка сделать непредусмотренный переход
Идентификационный номер клиента
Как избежать осложнений
Агрегаты как инструмент проверки правил
Расширение интерфейса API
Запрос правил для настройки пользовательского интерфейса
Возможность для внесения правил
Уточнение реализации
Наивная реализация
Переход от самой наивной стадии к созданию классов правил
Составление списка правил
Использование списка правил
Составление подсписков
Усовершенствование интерфейса API
Специальная настройка
Предоставление пользователю метаданных
Проблема подстать шаблону
Как обращаться со сложными правилами
Привязка к абстрактному представлению сохраняемости
Внедряемый интерфейс проверки достоверности
Альтернативные решения для проверки достоверности задним числом при сохранении
Повторное использование метаданных преобразования
Обобщения и анонимные методы как спасение
Другие подходы
Резюме

Часть III. Применение шаблонов архитектуры корпоративных программных приложений

Глава 8. Инфраструктура для сохраняемости

Требования к инфраструктуре сохраняемости
Место для хранения данных
Оперативная память
Файловая система
Объектная база данных
Реляционные базы данных
Один или несколько администраторов ресурсов
Другие факторы
Выбор решения и переход к его воплощению
Подход
Написание вручную заказного кода
Генерация заказного кода
Преобразование метаданных (объектно-реляционное преобразование)
Повторный выбор
Классификация
Вид модели предметной области
Вид объектно-реляционного преобразователя
Отправная точка
Акцент на интерфейсе API
Тип языка запросов
Улучшенная поддержка базы данных
Другие функциональные возможности
Классификация по шаблонам инфраструктуры
Тип метаданных для преобразования
Поля идентификации
Преобразование внешних ключей
Внедренное значение
Решения проблемы наследования
Карта идентичности
Единица работы
Загрузка по требованию или энергичная загрузка
Управление параллельным выполнением операций
Резюме

Глава 9. Приведение в действие преобразователя NHibernate

Основания для выбора преобразователя NHibernate
Краткое введение в NHibernate
Подготовка
Метаданные для преобразования
Небольшой пример интерфейса API
Транзакции
Требования к инфраструктуре сохраняемости
Высокий уровень неведения сохраняемости
Некоторые желательные свойства жизненного цикла постоянных объектов-сущностей
Аккуратное обращение с реляционной базой данных
Классификация
Вид модели предметной области
Вид объектно-реляционного преобразователя
Отправная точка
Акцент на интерфейсе API
Тип языка запросов
Улучшенная поддержка базы данных
Другие функциональные возможности
Классификация по шаблонам инфраструктуры
Тип метаданных для преобразования
Поля идентификации
Преобразование внешних ключей
Внедренное значение
Решения проблемы наследования
Карта идентичности
Единица работы
Загрузка по требованию или энергичная загрузка
Управление параллельным выполнением операций
Дополнительные возможности: перехватчики проверки достоверности
NHibernate и ППО
Краткий обзор сборок
Интерфейс ISession и хранилища
Интерфейс ISession, хранилища и транзакции
Чего мы достигли
Резюме

Часть IV. Что дальше

Глава 10. Рекомендуемые методы проектирования

Все дело в контексте
Слои и разделы
Основания для разбиения на разделы
Ограниченный контекст
Взаимосвязь между ограниченными контекстами и разделами
Расширение масштабов проектов ППО
Основание для разбиения модели предметной области на разделы - ориентация на службы
Введение в АОС
Что собой представляет АОС
Назначение АОС
Отличия АОС
Что такое служба
Что входит в службу
О значении четырех руководящих принципов АОС
Еще раз о том, что такое служба
Место объектной ориентации в АОС
Архитектура ''клиент-сервер'' и АОС
Односторонний асинхронный обмен сообщениями
Как АОС улучшает масштабируемость
Структура службы АОС
Взаимодействие службы с другими службами
АОС и недоступные службы
Сложные процессы обмена сообщениями
Масштабирование служб
Выводы
Инверсия управления и внесение зависимостей
Ни один из объектов не изолирован
Фабрики, реестры и указатели служб
Внесение зависимостей в конструктор
Внесение зависимостей в механизм установки
Инверсия управления
Внесение зависимостей в среде Spring.NET
Автосвязывание в среде PicoContainer.NET
Вложенные контейнеры
Сравнение шаблонов Service Locator и Dependency Injection
Выводы
Аспектно-ориентированное программирование
Из-за чего столько шума
Терминология АОП
АОП в .NET
Выводы
Резюме

Глава 11. Акцент на пользовательском интерфейсе

Предварительный эпилог
Шаблон Model-View-Controller
Пример: обувной магазин Джо
Упрощение интерфейсов представления с помощью адаптеров
Развязка контроллера от представления
Сочетание представлений и контроллеров
Чего все это стоит
Разработка Web-формы посредством тестирования
Предпосылки
Пример
Модель предметной области
РПТ графического пользовательского интерфейса
Реализация Web-формы
Выводы
Имитация средствами NMock
Преобразование и заключение в оболочку
Преобразование и заключение объектов в оболочку
Заключение МПО в оболочку МП
Преобразование МП в МПО
Организация отношений между объектами
Вопросы состояния
Заключительные соображения
Резюме
Эпилог

Часть V. Приложения

Приложение А. Другие виды моделей предметной области

Объектно-ориентированная модель данных, уровень развитого обслуживания и документы
В начале
Объектная ориентация и реляционные структуры данных
Модель предметной области и объектно-реляционное преобразование
Уровень обслуживания
Объединение на одном уровне
Приложение Джимми и АОС
Структура уровня обслуживания
Предоставление данных
Степень структурирования
Несколько слов о транзакциях
Выводы
Модель базы данных как модель предметной области
Место обитания сущностей
Функциональный анализ как основа разработки приложений
Прагматизм и нетрадиционный подход
Предпосылки и история вопроса
Краткий обзор архитектуры
Пример приложения Джимми для обработки заказов
Бизнес-правила размещения заказов
Некоторые заключительные соображения
Резюме

Приложение Б. Перечень рассмотренных шаблонов

Список литературы
Предметный указатель

Отзывы о книге

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

Скотт Беллуэр (Scott Bellware), авторитетный профессионал (Microsoft MVP) по C#, ведущий блог по проектированию на основе предметной области и разработке посредством тестирования

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

Джек Гринфилд (Jack Greenfield), разработчик архитектуры инструментария для предприятия, Visual Studio Team System, Microsoft

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

Тим Евальд (Tim Ewald), главный разработчик архитектуры программного обеспечения в компании Foliage Software Systems и автор книги Transactional COM+: Building Scalable Applications

"Эта книга вносит большой вклад в осуществление крупных, но важных идей проектирования на основе предметной области".

Флойд Маринеску (Floyd Marinescu), автор книги EJB Design Patterns и создатель Web-сайтов InfoQ.com и TheServerSide.com

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

Андерс Хесселлунд (Anders Hessellund), Копенгагенский университет информационных технологий, Дания

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

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

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

Эдвард Ежерски (Edward Jezierski), разработчик структуры шаблонов и практических методов Microsoft

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

Кристиан Кроухэрст (Christian Crowhurst), разработчик-аналитик

"Мне пришлось работать с Джимми над совместным проектом в течение 18 месяцев. Джимми действительно живет и работает по тем принципам, которые он проповедует. В книге он описывает свои действия на практике. В частности, он ежедневно пользуется объектно-реляционным преобразованием и преобразователем NHibernate, а разработка посредством тестирования помогает ему понять и вычленить бизнес-логику заказчика, а также убедиться в том, что заказчик получит проверенный, высококачественный код. Эта книга знакомит читателей с проверенными принципами. Пользуйтесь".

Дан Бистрём (Dan Bystrom), разработчик программного обеспечения, www.visual-design.se/blog

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

Пер-Ола Нильссон (Per-Ola Nilsson), руководитель отдела разработки и разработчик архитектуры программного обеспечения в компании Luvit

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

Матс Хеландер (Mats Helander), разработчик программного обеспечения, www.matshelander.com

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

Франс Боума (Frans Bouma), создатель средства генерации кода LLBLGen Pro, weblogs.asp.net/fbouma

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

Поль Гиленс (Paul Gielens), старший консультант в компании Capgemini, weblogs.asp.net/pgielens

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

Мартин Розен-Лидхольм (Martin Rosen-Lidholm), разработчик архитектуры программного обеспечения в компании Exense Healthcare

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

Ингмар Лундберг (Ingemar Lundberg), разработчик программного обеспечения www.ingolundberg.com

"Эта важная и своевременная книга должна стать настольной для всех, кто стремится разобраться в проектировании на основе предметной области на C#".

Грегори Янг (Gregory Young), авторитетный профессионал (Microsoft MVP) по C#, независимый консультант

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

Никлас Нильссон (Niclas Nilsson), разработчик программного обеспечения и преподаватель в компании Activa, он не ближний и даже не дальний родственник автора книги, а просто однофамилец

"В книге всесторонне описан процесс проектирования на основе предметной области (ППО - DDD) в практической плоскости посредством наведения мостов между различными абстрактными уровнями, начиная с общей бизнес-перспективы и заканчивая системным уровнем. Книга идеально подходит для разработчиков программного обеспечения и его архитектуры, поскольку написана в виде учебника или справочника. Автор отлично справился с задачей представления всех аспектов ППО не только в просветительской, но и в занимательной для чтения манере".

Гюнтер Ленц (Gunther Lenz), руководитель проекта и автор

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

Филип Нельсон (Philip Nelson), главный научный сотрудник компании PAi, xcskiwinn.org/community/blogs/panmanphil/defaulr.aspx

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

Джордж Хикс (George Hicks), старший разработчик компании Property Works

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

Андреас Бринк (Andreas Brink), разработчик программного обеспечения

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

Микаэль Фрайдлитц (Mikael Freidlitz), вице-президент по программам совершенствования содержимого и знаний в компании IASA

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

Род Джонсон (Rod Johnson), основатель компании Spring Framework, генеральный директор компании Interface21

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

Тронд-Эйрик Коллоэн (Trond-Eirik Kolloen), разработчик программного обеспечения и его архитектуры

"Может быть, мы уделим, наконец, внимание домашним проектам?"

Лотта, жена

"Ааа, дии, дии, дии, пии.." (Произношение заглавных букв книги на шведском языке)

Лео, четырехлетний сын

"Отец, ты действительно считаешь, что кто-то будет это читать?"

Тим, восьмилетний сын

Об авторе

Джимми Нильссон - владелец и управляющий шведской компании JNSK AB, он также автор двух книг и многочисленных статей в технических периодических изданиях. Джимми обучает специалистов и выступает с докладами на конференциях, но прежде всего, он разработчик почти с 20-летним стажем (www.jnsk.se/weblog/).

Предисловия

Создание программного обеспечения для предприятия - непростое дело. Несмотря на наличие множества инструментов и базовых средств разработки, упрощающих эту задачу, нам по-прежнему приходится решать, как использовать эти средства наилучшим образом. Для этого имеется немало подходов, но самое главное - знать, какой из них применять в конкретной ситуации, и вряд ли один подход пригодится на все случаи жизни. За последние несколько лет появилось целое поколение людей, занимающихся поиском подходов к проектированию приложений для предприятия и их документированию в виде шаблонов (соответствующий обзор можно посмотреть по адресу http://martinfowler.com/articles/enterprisePatterns/html). Те, кто занимается данной проблемой, в том числе и я, пытаются найти общие подходы и показать в своих трудах, как и когда их лучше всего применять. Результаты такой работы сильно разнятся, и поэтому читатель оказывается перед очень широким выбором.

Когда я приступил к работе над книгой Patterns of Enterprise Application Architecture (изд-во Addison-Wesley, 2002 год. Архитектура корпоративных программных приложений, пер. с англ. ИД "Вильямс", 2004 г.), то искал подобного рода рекомендации для проектирования в литературе по программным продуктам Microsoft. Я пытался найти хоть что-нибудь достойное внимания, но в конечном итоге обнаружил лишь одну редкую работу на данную тему - предыдущую книгу Джимми. Мне понравилась информативная манера изложения и стремление автора вникнуть в понятия, которые многие другие рассматривали весьма поверхностно. Именно Джимми решил воспользоваться идеями, выдвинутыми мной и другими авторами, и показать, как воплощать их в приложениях, создаваемых в .NET.

Основное внимание тех, кто занимается шаблонами для предприятий, сосредоточено на документировании удачных проектов. Мы увлечены и другим интересным направлением, являясь большими поклонниками гибких методов, охватывающих в том числе разработку посредством тестирования (РПТ - Test-Driven Development (TDD)) и рефакторинг кода. Эти идеи Джимми изложил в своей книге. Многие находят определенное противоречие в том, что те, кто занимается шаблонами, уделяют основное внимание проектированию, а те, кто занимается РПТ, - эволюции. Тот факт, что деятельность и тех и других вомногом пересекается, свидетельствует о том, что это не так, и Джимми попытался в своей книге связать воедино оба эти направления.

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

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

Мартин Фаулер (Martin Fowler), http://martinfowler.com

Самый лучший способ научиться проектированию на основе предметной области (ППО - Domain-Driven Design (DDD)) - сесть рядом с дружески настроенным, терпеливым, опытным практиком и поэтапно решать вместе с ним конкретные задачи. Именно так и происходит при чтении этой книги. Эта книга не открывает ничего особенно нового. Она лишь беспристрастно сообщает о личном опыте специалиста-практика и ряде современных практических методов, которые привлекли его внимание. Джимми Нильссон повторяет то, что многие из нас уже говорили не раз: ряд современных направлений, в частности, ППО, шаблоны архитектуры приложения для предприятия (PoEAA) и разработка посредством тестирования (РПТ) не являются альтернативой друг другу, а взаимно дополняют друг друга как элементы успешной разработки. Более того, все три направления оказываются сложнее, чем кажется на первый взгляд. Они требуют обширных и глубоких знаний. В этой книге уделяется некоторое внимание пропагандированию данных подходов, но большая ее частьвсе же посвящена подробностям их осуществления на практике.

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

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

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

Эта книга позволит многим читателям восполнить пробел в реализации выразительных объектных моделей на практике. Я лично извлек для себя ряд полезных способов продумывания вариантов применения технических структур и укрепил свои представления об особенностях выполнения ППО в среде .NET.

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

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

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

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

Эрик Эванс (Eric Evans)

Вступление: наведение мостов

На обложке этой книги представлена фотография моста через пролив Орезунд, соединяющего Швецию и Данию. Похоже, что на обложках всех книг по архитектуре программного обеспечения должны быть изображения мостов, но в данной книге для этого имеются дополнительные причины. Этот мост заменил паром, которым я переправлялся еще ребенком. Мне очень нравится каждый раз ездить по нему, хотя я проделывал это десятки раз. Между прочим, мой отец был среди тех, кто возводил самые высокие участки этого моста. Но самое главное, что эта книга во многом сродни наведению мостов - в данном случае между пользователями и разработчиками, конкретной предметной областью и программным обеспечением, логикой и хранением информации, теми, кто организует и ведет базы данных, и теми, кто занимается объектно-ориентированным программированием. Для того чтобы это вступление не выглядело слишком заумным, я, пожалуй, воздержусь от аналогии с шаблоном моста (Bridge) [GoF Design Patterns].

Назначение книги

Основное назначение этой книги состоит в том, чтобы показать, как строится четкая, но удобная с точки зрения сохраняемости модель предметной области (Domain Model). В ней также показано, как может выглядеть решение сохраняемости для такой модели предметной области и, в частности, как навести мост между такой моделью и базой данных. Иными словами, приступая к этой книге, я поставил перед собой цель перенести содержание книг Domain-Driven Design Эрика Эванса [Evans DDD] и Архитектура корпоративных программных приложений Мартина Фаулера [Fowler PoEAA] в определенный контекст. Проектирование на основе предметной области (ППО - Domain-Driven Design (DDD)) можно воспринимать как нечто абстрактное. Поэтому для пояснения, в частности, сохраняемости требуются вполне конкретные примеры. Мои примеры могут показаться довольно простыми, но они закладывают основание в качестве отправной точки. В этой книге не только поясняется, как пользоваться шаблонами, но и объясняется, как это можно делать, например, в объектно-реляционных преобразователях (O/R Mappers). Для меня стало вполне очевидно, что разработать архитектуру приложений на все случаи жизни невозможно. В этой связи шаблоны оказались достаточно обобщенными, чтобы неоднократно применять их в разных контекстах.

Основное внимание в книге уделяется не самим шаблонам, а их применению в качестве инструмента и языка для обсуждения различных аспектов проектирования. Но даже те читатели, которые не знакомы с шаблонами, получат в ходе чтения книги некоторое представление о них и, возможно, заинтересуются ими. Это же относится и к разработке посредством тестирования (РПТ - Test-Driven Development (TDD)). Пока еще не все разработчики заинтересовались этим методом.

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

Причины для написания книги

Написание моей первой книги [Nilsson NED] превратилось в трудное занятие в дополнение ко всем моим обычным проектам и обязанностям. В этой связи у меня появилась твердая уверенность, что я вряд ли буду писать еще одну книгу, но прошло время и у меня возникла потребность поделиться тем, что осталось еще невысказанным.

Я изменил свое решение после того, как недавно прочитал две книги. Первой из них была книга Архитектура корпоративных программных приложений Мартина Фаулера [Fowler PoEAA]. Эта книга вдохновила меня на очередное опробование модели предметной области после ряда предыдущих неудачных попыток. Затем я прочитал книгу Domain-Driven Design Эрика Эванса [Evans DDD]. Эта книга дала мне представление о том, как мыслить и действовать в процессе разработки, уделяя основное внимание предметной области, и, в какой-то степени, как применять шаблон модели предметной области.

Еще одно влияние на мое решение оказали курсы по шаблонам, которые я вел в течение двух лет. В процессе общения с учащимися и работы с учебным материалом у меня сложилось определенное представление о данном предмете. Мои взгляды на ППО претерпели изменения в ходе работы над весьма честолюбивым (и, к счастью, уже завершившимся) открытым проектом под названием Valhalla, который я разрабатывал вместе с Кристофером Скьолдборгом (Christopher Skjoldborg). (Большую часть работы выполнил Кристофер.)

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

Кому адресована книга

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

Тем не менее, интерес и увлеченность читателя способны восполнить недостающие знания и опыт работы в перечисленных выше областях.

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

Эта книга также может оказаться полезной для читателей как промежуточного, так и продвинутого уровня подготовки, а в какой-то степени и для начинающих.

Как организована книга

Эта книга состоит из следующих четырех частей.

Часть I. Основы

В этой части архитектура приложений и процессы рассматриваются в общих чертах. Основное внимание уделяется моделям предметной области и ППО [Evans DDD]. Кроме того, в ней вводятся понятия шаблонов и РПТ. В эту часть включены следующие главы.

Глава 1. Переоценка ценностей

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

Глава 2. Переход к шаблонам

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

Глава 3. РПТ и рефакторинг кода

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

Часть II. Прикладное ППО

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

Глава 4. Новая используемая по умолчанию архитектура

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

Глава 5. Проектирование на основе модели предметной области

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

Глава 6. Подготовка к инфраструктуре

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

Глава 7. Порядок устанавливают правила

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

Часть III. Применение шаблонов архитектуры корпоративных программных приложений

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

Глава 8. Инфраструктура для сохраняемости

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

Глава 9. Приведение в действие преобразователя NHibernate

Разделение решений на категории, выполненное в предыдущей главе, используется на примере решения сохраняемости, а именно преобразователя NHibernate [NHibernate].

Часть IV. Что дальше

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

Глава 10. Рекомендуемые методы проектирования

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

Глава 11. Акцент на пользовательском интерфейсе

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

Приложения

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

Основания для примеров на C#

Эту книгу ни в коем случае не следует рассматривать как учебник по C#. Тем не менее этот язык программирования понадобился мне для примеров. Я выбрал этот язык, главным образом, потому, что пользуюсь в настоящее время именно им, а большинство программирующих на VB.NET и Java могут свободно читать исходный текст и на C#.

Что же касается конкретной версии, то большая часть кода в приведенных примерах вполне работоспособна в версиях C# 1.1 и 2.0, хотя в редких случаях отдельные фрагменты кода относятся к версии 2.0.

Темы, не охваченные в книге

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

Распределение

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

Усовершенствованное моделирование

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

finally{}

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

Дополнительную информацию о книге можно найти по адресу http://www.jnsk.se/adddp. Если вернуться к наведению мостов, то фотография моста через пролив Орезунд была сделана моим другом Магнусом фон Шенком (Magnus von Schenk) во время одной из его прогулок по морю под парусом.

Написать эту книгу оказалось легче, чем первую, тем не менее, она стоила мне немало крови, пота и слез. Надеюсь, что она поможет вам сберечь немного того, другого и третьего. Желаю вам получить удовольствие от книги. Удачи!

Джимми Нильссон

Комментарии