Patterns of Enterprise Application Architecture: як читати книгу Фаулера і не загубитися
Вітаю, мене звати Віталій Містряков, я спеціаліст компанії Digicode.
Книгу Мартіна Фаулера Patterns of Enterprise Application Architecture часто рекомендують авторитетні інженери, тож я вирішив прочитати її самостійно. Під час читання з’ясувалося, що книга, попри свою цінність, може бути складною для сприйняття: через вік, застарілі технологічні приклади та абстрактність окремих ідей.
Ця стаття — спроба структурувати ключові думки книги й подати їх у вигляді супроводу до читання. Вона орієнтована на читачів із базовим технічним бекґраундом і не має на меті детально пояснювати всі терміни.
Текст є моєю суб’єктивною інтерпретацією прочитаного, тому відкритий до зауважень і критики. Стаття не претендує на повний огляд книги — це стислий конспект, який я насамперед робив для себе, але який може бути корисним і іншим.
Тож по структурі данної доповіді:
1. Глобальний короткий аналіз розділів та як всприймати книгу
2. Короткий саммарі по кожному розділі, основні лейкмотиви та ідеї
3. Коротко про паттерни як їх описує фаулер
4. Особистий відгук
РОЗДІЛ 1. Загальна структура книги (як вона логічно побудована)
Фаулер зробив цю книгу як 2 в 1:
A) Part 1 — «Narratives» (розділи
B) Part 2 — «Patterns» (розділи
Це енциклопедія патернів. Та детально описане технічне рішення для проблем описаних в першій частині. Також опис того як паттерни працюють з першої частини книги
РОЗДІЛ 2. Короткий саммарі розділів
Chapter 1. Layering.
Фаулер пояснює, що шарування — базовий спосіб розламати складну систему на керовані частини. Типова enterprise-схема: Presentation / Domain / Data Source, де верхні шари використовують нижні, але не навпаки. Ідейно дуже схожа на книгу роберта мартіна чиста архітектура. Якщо читали її ви дуже просто зрозумієте ідею цієї глави
Chapter 2. Organizing Domain Logic
Глава про те, де повинна жити бізнес-логіка, і що це рішення визначає всю архітектуру. Фаулер порівнює три підходи: Transaction Script (процедури), Domain Model (об’єкти з поведінкою) та Table Module (логіка навколо таблиць/Record Set). Він показує, що вибір залежить від складності домену, досвіду команди і платформи, і що «універсальної формули» немає. Формує 3 фундаментальні підходи, які потім оформляться у Chapter 9
Chapter 3. Mapping to Relational Databases
В цій главі розповідається про ціну інтеграції з базою данних, об’єктна модель і реляційна БД мають різний спосіб мислення, і це не виправляється магією ORM. Глава дає контекст, чому виникають mapping-патерни: читання даних у об’єкти, проблема структурної невідповідності, контроль ідентичності, зв’язків та спадкування. Він підводить до думки, що мапінг треба ізолювати від домену, і що складний домен майже завжди тягне складніший data source layer. Згадуються паттерни Data mapper, active record та gateway. Також ця глава стає основою для глав
Chapter 4. Web Presentation
Глава про те, що web-UI — повноцінний presentation layer, який легко заражається бізнес-логікою. Фаулер розбирає базові підходи: як будувати views (template/transform/two-step) і як обробляти запити (page/front controller). Головний ризик — коли в UI опиняються доменні правила. Також є основою для Chapter 14 (Web Presentation Patterns)
Chapter 5 — Concurrency
Фаулер показує, що concurrency — це не про потоки, а про одночасну роботу кількох користувачів з одними даними. Типові проблеми на кшталт lost update виникають навіть у найпростішому CRUD. Рішення — правильно визначити unit of work, транзакційні межі та вибирати між оптимістичним/песимістичним контролем. Він підкреслює: транзакції допомагають, але не рятують довгі бізнес-процеси. Це підготовка до offline concurrency (Chapter 16).
Chapter 6. Session State
Глава пояснює, чому stateless — це благо, бо так легше масштабувати й підтримувати систему. Але бізнес-процеси часто вимагають стан: логін, кошик, багатокрокові форми. Тому Фаулер обговорює варіанти session state такі як Client-side Session State, Server-side Session State, Database-backed Session State, це також підготовка до глави 17
Chapter 7. Distribution Strategies
Тут Фаулер жорстко пояснює: розподіленість додає складність і повільність, а мережа не «прозора». Він показує, що «рознести domain по сервісах» звучить красиво, але зазвичай породжує проблеми. Краще робити coarse-grained межі і мінімізувати remote-виклики. Глава формує правильне ставлення: distribute тільки якщо мусиш. Оскільки це завжди жертва. Підготовка до глави 15
Chapter 8 — Putting It All Together
Це «інструкція складання»: як комбінувати ідеї попередніх глав у цілісну архітектуру. Фаулер показує типову схему: presentation → service boundary → domain → data source, і пояснює, чому domain має бути центром системи. Тут немає нових патернів — є логіка прийняття рішень та компромісів. Головна цінність: патерни не існують окремо, вони працюють лише в системі
Chapter 9 — Domain Logic Patterns
Це формалізація вибору з Chapter 2: Transaction Script, Domain Model, Table Module, Service Layer як патерни з чітким «коли застосовувати». Transaction Script — найпростіший старт, але погано росте через дублювання і заплутування. Domain Model — дорожчий в освоєнні, але дає структуру для складного бізнесу (стратегії, поліморфізм, розширення). Table Module — середній шлях, зручний у середовищах з Record Set . Service Layer — границя use-case API та місце для транзакцій/безпеки
Chapter 10 — Data Source Architectural Patterns
Глава пояснює, як виглядає шар доступу до даних і чому він не повинен протікати в домен. Table Data Gateway і Row Data Gateway — процедурно-табличні підходи, зручні для простих систем і Transaction Script. Active Record змішує дані й доступ до БД в одному класі — швидко і практично, але гірше для багатого домену. Data Mapper відокремлює domain від persistence, що майже необхідно для серйозного Domain Model. Цей розділ — ключ до розуміння «з чого насправді зроблений ORM»
Chapter 11 — Object-Relational Behavioral Patterns
Фаулер розбирає поведінкові патерни, без яких ORM перетворюється на хаос. Unit of Work збирає зміни об’єктів і комітить їх узгоджено, а Identity Map гарантує «один DB-рядок = один об’єкт у пам’яті». Lazy Load відкладає завантаження даних до моменту фактичної потреби, але може породжувати N+1 та «магічні» запити. Разом ці патерни роблять persistence керованим і передбачуваним.
Chapter 12. Object-Relational Structural Patterns
Як не зламати систему неправильним маппінгом. В основі це опис механік, які вже закладені в ORM, якщо коротко то те як мапити sql структури в ооп об’єкти. Розповідає про паттерни які дозволяють забезпечити маппінг в різних кейсах
Chapter 13 — Object-Relational Metadata Mapping Patterns
Глава піднімає абстракцію: як прибрати мапінг та запити з «ручного коду» і зробити їх керованими. Metadata Mapping виносить правила мапінгу в конфіг/метадані, щоб не розмазувати їх по програмі. Query Object дозволяє будувати запити як об’єкти, замість строкового SQL всюди (orm підхід сучасний). Repository дає domain-орієнтований інтерфейс доступу до об’єктів, приховуючи деталі від бізнес логіки.
Chapter 14 — Web Presentation Patterns
Фаулер деталізує, як структурувати presentation layer патернами: MVC, Page Controller, Front Controller, Application Controller та view-патерни (Template/Transform/Two Step). Він підкреслює, що контролери вирішують routing і orchestration, а не бізнес-логіку. Тут видно «чому фреймворки такі»: багато з них — прямі реалізації Front Controller. Основна мета — контроль потоку запиту і ізоляція UI від домену
Chapter 15 — Distribution Patterns
По духу анти-мікросервісний, поснює ціну розподілення та які негативні наслідки має передавання данних по мережі. Remote Facade робить інтерфейс coarse-grained і use-case орієнтованим, щоб не було chatty викликів. Data Transfer Object (DTO) переносить дані між процесами простими структурами без поведінки, щоб не тягнути Domain Model «по дроту». Суть глави: мережа дорога, тому зменшуй кількість викликів і передавай тільки те, що потрібно. Сьогодні це буквально основа REST/gRPC контрактів і мікросервісних boundary.
Chapter 16 — Offline Concurrency Patterns
Автор пояснює, що в довгих бізнес-процесах треба ловити конфлікти не блокуваннями, а спеціальними механізмами: найчастіше Optimistic Offline Lock (версії/таймстемпи), інколи Pessimistic Offline Lock (явне резервування), а також підходи типу Coarse-Grained Lock та Implicit Lock, щоб контролювати конфлікти на рівні агрегатів, а не окремих рядків. По суті, ця глава вчить, як робити систему стійкою до «останній запис переміг» і не ламати дані, коли кілька людей змінюють одне й те саме
Chapter 17 — Session State Patterns
Це практичне продовження Chapter 6: як зберігати стан між запитами. Фаулер описує Client Session State, Server Session State, Database Session State як різні компроміси між масштабуванням, безпекою і простотою. Client-side дає stateless сервер, але вимагає обережності із довірою та розміром. Server-side простий, але погано масштабується без sticky sessions або реплікації. Database/shared-state стабільніший для кластера, але додає latency і потребує грамотного lifecycle management.
Chapter 18 — Base Patterns
Це «цеглинки», з яких збираються інші рішення: Gateway, Mapper, Layer Supertype, Separated Interface, Registry, Value Object, Money, Special Case, Plugin, Service Stub, Record Set. Фаулер показує базові прийоми ізоляції інфраструктури, трансформації моделей і керування залежностями. Value Object і Money важливі для правильного domain-дизайну, Special Case прибирає null-пекло, Plugin дає розширюваність, Service Stub підтримує тести. Record Set і Registry — більше історично-енвайронментні патерни, але ідеї досі зустрічаються. Цей розділ працює як «словник деталей», щоб читач розумів терміни в інших главах
РОЗДІЛ 3. Основні паттерни
В книзі описана велика кількість паттернів (40+) тому в межах статі буде складно описати і реалізувати кожен. Тому на мою думку обрав основні паттерни на яких будується книга та постарався коротко їх переказати
Domain Logic Patterns (серце книги)
- Transaction Script
Це коли кожну бізнес-дію роблять «одним великим скриптом».
Поки все просте, працює і навіть зручно.
Але як тільки з’являється складніша логіка, усе починає повторюватися, розповзатися, і код швидко стає важко підтримувати.
Тобто одна процедура це набір непов’язаної бізнес-логіки з іншими процедурами
- Domain Model
Це коли домен це ооп структура, яка інкапсулює данні і поведінку бізнес логіки для сутностей предметної області.
Логіка розкладається по сутностях/Value Objects, тому систему легше масштабувати і розширювати.. DDD — зробив цей підхід стандартним для складних бізнес моделей
- Table Module
Підхід «один клас = одна таблиця», який працює з наборами записів (record set). Це такий компроміс: логіка вже структурована краще, ніж у скриптах, але без важкого OO і доменних трюків.
- Service Layer
Шар use-case логіки між presentation і domain: місце, де живе сценарій, а не UI. Тут зручно робити orchestration, транзакції, security, інтеграції — і не пускати контролери напряму в доменні об’єкти. Типова історія для NestJS/Spring сервісів, а також «application layer» у Clean Architecture / DDD.
Data Source Patterns (зв’язок домену з БД)
- Data Mapper
Це коли між доменом і базою є окремий шар мапінгу: доменні об’єкти живуть своїм життям, а persistence — своїм.
Плюс: домен залишається «чистим» і не знає нічого про SQL/таблиці. Мінус: мапінг і інфраструктура стають складнішими.
- Active Record
В цьому паттерні об’єкт = рядок таблиці, і він сам уміє save() / load() / delete().
- Gateway (Table/Row Data Gateway)
Це клас-двері до БД, який ховає SQL і дає контрольований доступ до таблиць/рядків.
Логіка роботи з даними винесена окремо, домен/сервіси не залежать від конкретного SQL, плюс легко мокати і тестувати.
Зазвичай це виглядає як DAO / repositories / db adapters.
Object-Relational «механіка ORM» (must-know)
- Unit of Work
Патерн, який збирає всі зміни об’єктів за один бізнес-запит і робить commit одним пакетом.
Так ORM тримає транзакційні межі, консистентність і правильний порядок INSERT/UPDATE/DELETE.
- Identity Map
Гарантує, що 1 рядок у БД = 1 об’єкт у пам’яті в межах контексту.
Живе як перший рівень кешу в ORM.
- Lazy Load
Популярний паттерн сьогодні і поза межами контексту СУБД. Каже що потрібно підтягувати зв’язки лише тоді, коли вони реально потрібні.
Економить ресурси, але легко приводить до N+1 і «прихованого SQL» — треба свідомо контролювати.
Типово реалізується через ORM proxies, і концептуально схоже на те, як працюють GraphQL resolvers.
Query/Repository абстракції (як не залити домен SQL-ом)
- Repository
Репозиторій — це інтерфейс «колекції» доменних об’єктів над базою.
Це колекція обʼєктів, яка виглядає як in-memory, але насправді ходить у БД. Часто можна побачити цей паттерн в вигляді методів: findById findAll add remove
Класика для DDD / Clean Architecture
- Query Object
Тут сам запит оформлюється як об’єкт, який можна будувати і комбінувати. Обʼєкт, представляє запит, і його можна передавати/комбінувати/тестувати, а не склеювати SQL строками. Приклад це query builder-и і Specification pattern.
Web Presentation ядро
- Front Controller
Одна точка входу для всіх HTTP-запитів.
Централізує routing, auth, логування, помилки — і прибирає дублювання між контролерами. Сьогодні можна побачити в різних middleware пайпах
- MVC (Model-View-Controller)
Розділення «керування», «дані/логіка» і «відображення».
UI не має знати, як працює домен — він лише викликає use-case і показує результат.
Distribution (коли система рознесена по мережі)
1) Remote Facade
Це coarse-grained API для викликів через мережу.
Менше дрібних запитів → менше latency → менше «чаттеру» між сервісами.
Зазвичай це microservice endpoints, application services,
2) Data Transfer Object (DTO)
Простий контейнер для даних для передачі між процесами.
Доменну модель не варто «видавати напряму»: це небезпечно, дорого і погано версіонується. Cучасна база і стандарт
Concurrency (офлайн/довгі транзакції)
- Optimistic Offline Lock
Підхід через version/revision, щоб ловити конфлікти оновлень.
Ми не блокуємо дані — ми перевіряємо перед commit, що їх не змінили паралельно.
Реалізація: version column, ETag, optimistic concurrency control у системах
Session State (де жити стану)
1) Client Session State / Server Session State / Database Session State
Стан можна тримати на клієнті, на сервері, або в БД.
State дає зручність бізнесу, але ускладнює масштабування, інвалідацію і підтримку.
Приклади: JWT (client), Redis sessions (server/shared), DB state (рідше).
РОЗДІЛ 4. Висновок і персональне враження від книги
Попри свій вік, Patterns of Enterprise Application Architecture залишається актуальною з точки зору ідей і підходів. Водночас варто враховувати, що частина технологічних прикладів застаріла, а деякі патерни з часом еволюціонували або набули інших форм. Через це окремі розділи можуть здаватися абстрактними й важкими для швидкого застосування в сучасному контексті.
У цій статті розглянуто лише частину матеріалу книги, тож вона не замінює повноцінне читання. Якщо вас зацікавили ідеї, рекомендую ознайомитися з оригіналом і сформувати власне бачення.
12 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів