TGViewer
Beer::Code🍺 Beer::Code🍺 @beerphp · 3.64K subscribers
Post #123 2.84K
Read, Write, Partial Update

Наступна відома проблема, коли ми намагаємось використовувати один і той самий обʼєкт як для читання (наприклад представлення на frontend) так і для запису (створення, оновлення).

👉
Візьмемо іншу сутність в рамках нашого створення замолення — Customer. Побудуємо його з низки Value Objects щоб гарантувати, що дані завжди валідні.

$customer = new Customer(
new CustomerId(uniqid()),
new Email($request->email),
new Name($request->name)),
new Password($request->password))
);

$repository->save($customer);

Які ж можуть виникнути проблеми?

1️⃣ Щось, що ми не хочемо відображати

Якщо для відображення ми будемо використовувати той самий обʼєкт Customer, існує ризик, що у відповідь потраплять зайві дані.

interface CustomerRepository
{
public function save(Customer $customer): void;
public function get(string $email): Customer;
}


Наприклад захешований пароль


{
"customerId": "5f2b...",
"email": "jane@doe.com",
"name": "Jane Doe",
"password": "$2y$10$..."
}


Так, можемо по місцю зробити щось на кшталт:

final readonly class Customer
{
// ...

public function serialize(): array
{
return [
'email' => $this->email,
'name' => $this->name,
];
}
}


2️⃣ Зміна правил валідації

Їдемо далі. Наші перевірки в Value Objects можуть змінюватись з часом. В якийсь момент, ми можемо зробити їх більш жорсткими. В базі даних можуть зберігатись записи, котрі можуть не пройти правила нової валідації, якщо ми будемо використовувати один і той самий обʼєкт для читання і для запису. Тут починаються трюки з Reflection. Вже не так райдужно.

3️⃣ Додаткові дані для відображення

Наступна проблема, коли для відображення нам потрібна інформація, котра не міститься в поточному обʼєкті. Наприклад, кількість замовлень.

[
...$customerRepository->getById($customerId),
...['orders_count' => $orderRepository->count($customerId)]
]


Варіант робочий, проте ми тут робимо 2 запити до бази даних, хоча потенційно можна зробити один.

4️⃣ Чи дійсно створення та оновлення це одне і те саме?

При створенні нового Customer ми очікуємо email, name та password. Але, наприклад, при зміні імені, що ми маємо передавати в полі пароля. Чи навпаки, при зміні пароля нам потрібна специфічна логіка (запит на зміну, надсилання токена тощо).

interface CustomerRepository
{
public function save(Customer $user): void;
public function update(Customer $user): void;
}

// Updating name
$customer = new Customer(
$request->email,
$request->name,
'а що тут робити з паролем?',
);

$repository->update($customer);


🤓 Щоб вирішити ці проблеми, доцільно використовувати окремі моделі для різних операцій. Наприклад:

final readonly class CustomerRead
{
public function __construct(
public CustomerId $customerId,
public Email $email,
public Name $name,
public int $orderCount,
) {}
}

interface CustomerReadRepository
{
public function get(CustomerId $customerId): CustomerRead;
}

Або для оновлення даних:

final readonly class CustomerNameUpdate
{
public function __construct(
public CustomerId $customerId,
public Name $name,
)
}

interface CustomerRepository
{
public function save(Customer $customer): void;
public function updateData(CustomerNameUpdate $customerNameUpdate): void;
public function updatePassword(CustomerPasswordUpdate $customerPasswordUpdate): void;
}


✏️ Write model забезпечує дотримання інваріантів і консистентність даних. Оскільки тут ми не паримось як саме будемо виводити ці дані - це дозволяє нам робити обʼєкт маленьким і конкретним.

📖 Read model дає можливість отримати всю необхідну інформацію, потрібну для конкретного відображення чи перегляду.

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

#backend #architecture #middle #source
  • 👍 32
  • 🔥 5
  • 🙊 3
  • ⚡ 1
More from @beerphp
  1. Sep 22, 2026Anthropic випустила Opus 5.5 За словами Anthropic, на більшості задач вона працює на рівні…
  2. Sep 21, 2026Доречі, цього тижня буду проводити НОВИЙ воркшоп Harness Engineering - 24 і 26 вересня. Од…
  3. Sep 21, 2026Хочу поділитись своєю мотивацією На тому тижні був воркшоп Agentic Engineering Workflow Ко…
  4. Sep 20, 2026Post #198
  5. Sep 14, 2026Не можу не поділитись, вчора отримав такий відгук Це прям паливо заради якого хочеться про…
  6. Sep 13, 2026І знову я зі своїм воркшопом 🙂 Але перед цим - попереджаю і кажу чесно, канал і соцмережі…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →