Думаю, що не треба наголошувати, що reqeust до зовнішньої мережі буде працювати значно повільніше (і менш стабільно) ніж звернення до локальної памʼяті або локальної мережі. Різниця в часі щонайменше в 7 разів. Саме тому архітектура вашого застосунку, ваш код, має це враховувати.
✅ Чітко і явно відокремлюйте виклики через зовнішню мережу.
Ми постійно використовуємо DI контейнер для зручності, тому клієнтський код десь в application layer, може виглядати достатньо звично:
// client code after DI container wiring
$order = new Order($id, $userId, $total);
$this->orderRepository->save($order);
❗️️️️️️️Проте, всередині може бути досить велика різниця:
Одна реалізація [gist]
final readonly class OrderRepository
{
public function __construct(
private PostgresConnection $connection
)
{
}
public function save(Order $order)
{
$this->connection->execute('INSERT INTO orders (id, user_id, total) VALUES (?, ?, ?)', [
$order->id(),
$order->userId(),
$order->total()
]);
}
}
Зовсім інша реалізація [gist]
final readonly class OrderRepository
{
public function __construct(
private OrderApiClient $client
)
{
}
public function save(Order $order)
{
$this->client->createOrder($order);
}
}
📍️️️️️️ При такій реалізації в клієнтському коді досить важко передбачити виклик через зовнішню мережу. Допоможіть собі майбутньому і іншим програмістам в вашому проекті чітко зрозуміти з чим саме зараз ви зараз працюєте.
🔥 Введіть неймінг, котрий явно буде кричати про себе, говорити що виклик зовнішній:
OrderProvider, OrderGateway, OrderIntegration, etc.
Будь яка конвенція, котра буде команді довподоби, але вона має чітко відрізнятись від:
OrderRepository, OrderStorage, etc.
🤓 Можливо передача інфомації за допомогою квантових частинок дозволить нам робити це миттєво в якомусь майбутньому, проте на даному етапі ми жорстко обмежені швидкістю світла.
✅ Намагайтесь отримати одразу всі необхідні дані
Якщо вже виконуєте зовнішій виклик, намагайтесь повернути всі потрібні дані в одному запиті. Cхоже на вирішення класичної проблеми n+1.
[gist]
employees = $this->employeeProvider->getList($limit, $offset);
foreach ($employees as $employee) {
$department = $this->departmentProvider->getById(
$employee->getDepartmentId(),
);
// do something with department
}
Проти [gist]
$employees = $this->employeeProvider->getList($limit, $offset);
$departments = $this->departmentProvider->getAll();
// prepare a map of department id to department
foreach ($employees as $employee) {
$department = $departments[$employee->getDepartmentId()];
// do something with department
}
✅ Кешування – ваш друг, але будьте з ним обережні
Якщо ви досить часто запитуєте одні і ті самі дані, а в свою чергу, вони відносно рідко змінюються - кеш може бути чудовим рішенням. Він одночасно зменшить час на виклик, обробку даних і навантаження на мережу.
❗️Обовʼязково приділіть час для узгодження стратегії інвалідації кеша.
✅ Інвертуйте потік даних
Замість того, щоб кожного разу опитувати інші сервіси, ви можете використовувати патерн Pub/Sub та зберігайти дані локально (в тому числі в кеші). Звичайно, це ускладнює архітектуру, звичайно, це підійде не для всіх задач. Але памʼятайте про цей прийом, він може досить елегантно вирішити проблему в вашому проекті.
#php #architecture #middle #source