Пример чистой архитектуры на оценку

Обсуждаем, как правильно строить приложения
Wizard
Сообщения: 173
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение Wizard » 2019.10.05, 09:47

ElisDN писал(а):
2019.10.05, 00:19
А если бы во фреймворк коммитили сто программистов наугад без тестов... то это была бы совсем другая история.
Ни в коем случае не пытаюсь оспорить достоинства тестов. Написав тесты разработчик может быть уверен в том что код соответствует требованиям, работает правильно.

Но как тест может повлиять на качество если я создам нечто и покрою тестами

Код: Выделить всё

class X
{
    public function z()
    {
        // много кода...
        
        for ($i = 0; 53 > $i; $i++) {
            if ($i == 13) {
                ///
            }
        }
    }

    public function y()
    {
        // много кода...
    }
}
я могу быть уверен в что код рабочий, но единственная ли это цель качественного кода? Максимум на что они могут повлиять это на структуру - для того что бы было легче доказать наличие ошибок прийдется декомпозировать методы, создать явные зависимости...

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

Ни как не могу согласиться с тем что знаком качества является рабочий код. А тесты иного определить не могут...
Последний раз редактировалось Wizard 2019.10.05, 10:21, всего редактировалось 1 раз.

Аватара пользователя
maleks
Сообщения: 1827
Зарегистрирован: 2012.12.26, 12:56

Re: Пример чистой архитектуры на оценку

Сообщение maleks » 2019.10.05, 10:20

anton_z писал(а):
2019.10.04, 14:41
Смотрите. Соображения по архитектуре в README.md.
Спасибо. Гляну чуток попозже.
yiijeka писал(а):
2019.10.04, 15:28
Вся проблема в том, что придёт новый программист и 99% что он заюзает $post = new Post; if ( $post-load() && $post->save()) и вся ваша clean архитектура идёт лесом, так как она в корне уже имеет проблемы - публичный API.

ИМХО чистая архитектура - одна задача - один способ ...
Ну в описании архитектуры не встречал еще и такого требования.
Она больше о внутреннем качестве.
Насчет ошибок вновь входящих, так у них будет регламент как раз по этой архитектуре.
Например без регламента, было бы как сейчас, бардак во всем, ui код и код запросов к БД и логика везде , во вьюхах, виджетах, контроллерах, компонентах, конфигах и т.д., и как тут что то объяснять не делать?
А с докой и примерами есть на что сразу соориентировать и указать как делать.
Это имхо лучше чем то что часто например встречаю всякие необъяснимые требования типа - "ничего не писать в AR"
Yii2 universal module sceleton - for basic and advanced templates

Аватара пользователя
maleks
Сообщения: 1827
Зарегистрирован: 2012.12.26, 12:56

Re: Пример чистой архитектуры на оценку

Сообщение maleks » 2019.10.05, 10:42

Wizard писал(а):
2019.10.05, 09:47
Ни как не могу согласиться с тем что знаком качества является рабочий код. А тесты иного определить не могут...
Более троллерский вопрос - как вообще без тестов можно давать гарантии что код рабочий?
Вы когда начнете писать тесты увидите что чем более говнястый код вам надо протестировать тем сложнее это сделать. Те же например просто классы должны тестироваться чистыми unit тестами, вообще без базы, поэтому ж я выше с этим репозиторием и вожусь, т.к. надо уйти от $ar->save() в usecase-ах и домене.
Yii2 universal module sceleton - for basic and advanced templates

Аватара пользователя
ElisDN
Сообщения: 5452
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение ElisDN » 2019.10.05, 11:06

Wizard писал(а):
2019.10.05, 09:47
...единственная ли это цель качественного кода?
Это уже вопрос, что и как считать качественным.

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

Качество код - это его понятность для программистов (переменные $price и $cost, а не $a1, $a2), слабосвязанность для добавления новых фич, явность всех зявисимостей.
Wizard писал(а):
2019.10.05, 09:47
Но как тест может повлиять на качество если я создам нечто и покрою тестами...
я могу быть уверен в что код рабочий, но единственная ли это цель качественного кода?
Максимум на что они могут повлиять это на структуру - для того что бы было легче доказать наличие ошибок прийдется декомпозировать методы, создать явные зависимости...
Ну вы здесь хотя-бы в отдельный класс код вынесли, чтобы его можно было юнит-тестами протестировать. Люди без тестов весь код бы в контроллер навалили.

Или вот человек без юнит-тестов в User методы attemptConfirmation и attemptEmailChange сочинил и в beforeSave кода добавил. И там все методы неявно настройки из Yii::$app->getModule('user') дёргают, в Yii::$app->session->setFlash пишут, через Yii::$app->mailer письма посылают и Yii::$app->user->login($this) делают. Протестировать это юнит-тестами очень геморройно. А если бы он попробовал к этому сначала чистые юнит-тесты написать, то весьма вероятно, что структуру бы сам переделал на более явную.
Wizard писал(а):
2019.10.05, 09:47
Все популярные фреймворки покрыты тестами, и вы утверждаете что все они от этого работают корректно, в них нет ошибок а код автоматически становиться качественным (в совокупности всех характеристик определяющих качество)?
Если тесты пишут до или вместе с кодом, то тесты влияют на код. Цикломатическая сложность кода, связанность и подобные характеристики улучшаются. И при добавлении новой функциональности хочется меньше ломать старые тесты, поэтому начинаешь делать структуру по SOLID.

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

Так что ковыряясь в продукте с тестами я уверен на 80%, что ничего не сломаю, а без тестов только на 20%.

Wizard
Сообщения: 173
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение Wizard » 2019.10.05, 11:22

ElisDN писал(а):
2019.10.05, 11:06
Если тесты пишут до или вместе с кодом, то тесты влияют на код. Цикломатическая сложность кода, связанность и подобные характеристики улучшаются. И при добавлении новой функциональности хочется меньше ломать старые тесты, поэтому начинаешь делать структуру по SOLID.
не следует ли из этого что тесты в большей степени влияют на архитектуру чем непосредственно на сам код?

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

Аватара пользователя
ElisDN
Сообщения: 5452
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение ElisDN » 2019.10.05, 12:22

Wizard писал(а):
2019.10.05, 11:22
не следует ли из этого что тесты в большей степени влияют на архитектуру чем непосредственно на сам код?
Рабочим код должен быть по умолчанию, а тесты помогают разработчику в этом убедиться. Но рабочим может быть как лапшекод так и чистый, качественный код.
Возьмём типовой лапшекод во вьюхе. Его можно покрыть интеграционными тестами. Да, они проверят работоспособность, но ничего не улучшат. А юнит-тестами уже не получится.

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

Wizard
Сообщения: 173
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение Wizard » 2019.10.05, 12:36

ElisDN писал(а):
2019.10.05, 12:22
Wizard писал(а):
2019.10.05, 11:22
не следует ли из этого что тесты в большей степени влияют на архитектуру чем непосредственно на сам код?
Рабочим код должен быть по умолчанию, а тесты помогают разработчику в этом убедиться. Но рабочим может быть как лапшекод так и чистый, качественный код.
Возьмём типовой лапшекод во вьюхе. Его можно покрыть интеграционными тестами. Да, они проверят работоспособность, но ничего не улучшат. А юнит-тестами уже не получится.

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

Юнит-тесты если и навязывают приложению становиться компонентным, то качество компонентов все еще ничем не гарантированно. Мы убедились что все юниты лежать по полочкам, приложение ведет себя предсказуемо и ожидаемо. Очевидно какие то части приложения стали более независимыми, некоторые из них можно переиспользовать. Если от такого подхода выгода? Конечно! Но вернемся к качеству - чем оно гарантированно зная только о том что у нас есть юнит-тесты? По прежнему приложение можно назвать рабочим. Это хорошо... но про качество говорить рано.

Аватара пользователя
samdark
Администратор
Сообщения: 9227
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение samdark » 2019.10.05, 13:07

Более троллерский вопрос - как вообще без тестов можно давать гарантии что код рабочий?

https://ru.wikipedia.org/wiki/Формальная_верификация (см. формальные методы и доказательное программирование).
Те же например просто классы должны тестироваться чистыми unit тестами, вообще без базы
В тестировании с базой есть свои плюсы и минусы. Минусы — медленно. Плюсы — тестируем реальную интеграцию, а не контракт из моков.
Юнит-тестами по определению можно покрыть только код, вынесенный отдельно и декомпозированный на независимые юниты.
Или по-чёрному намокать. Или почитать определение и понять что юнит (модуль) не ограничен одним классом и что это выдумали фанатики.
Но вернемся к качеству - чем оно гарантированно зная только о том что у нас есть юнит-тесты? По прежнему приложение можно назвать рабочим. Это хорошо... но про качество говорить рано.
Полностью поддерживаю. Даже 100% покрытие не гарантирует что протестировано действительно всё. Рабочим называется приложение без фатальных косяков, разнится лишь степень уверенности в том, что их нет.

Wizard
Сообщения: 173
Зарегистрирован: 2018.02.05, 13:41
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение Wizard » 2019.10.05, 13:11

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

Выдержка из литературы о качестве (необязательно истина но хоть что то)

Внешние характеристики
Корректность
Практичность
Эффективность
Надежность
Целостность
Адаптируемость
Правильность
Живучесть
Внутренние характеристики (они очевидно нас интересуют больше)
Удобство сопровождения
Гибкость
Портируемость
Возможность повторного использования
Удобочитаемость
Тестируемость
Понятность
Не смотря на то что по каждому из пунктов можно найти отдельную литературу, когда я пишу юнит-тесты какие характеристики я покрываю? Не слишком ли завышены ожидания на юнит-тесты в целях контроля качества если учесть что в той же литературе указаны относительно не высокие показатели обнаружение ошибок посредством тестирования в сравнение с той же инспекцией кода? Получаеться тестирование в полной мере не выполняет своего предназначение не говоря уже о том что бы полагаться на то что они повышают качество.

Аватара пользователя
ElisDN
Сообщения: 5452
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение ElisDN » 2019.10.05, 17:17

Wizard писал(а):
2019.10.05, 12:36
Юнит-тесты если и навязывают приложению становиться компонентным, то качество компонентов все еще ничем не гарантированно. Мы убедились что все юниты лежать по полочкам, приложение ведет себя предсказуемо и ожидаемо. Очевидно какие то части приложения стали более независимыми, некоторые из них можно переиспользовать. Если от такого подхода выгода? Конечно! Но вернемся к качеству - чем оно гарантированно зная только о том что у нас есть юнит-тесты? По прежнему приложение можно назвать рабочим. Это хорошо... но про качество говорить рано.
Тогда сначала скажите, что именно является для вас "качеством" и как вы его измеряете без тестов.
Wizard писал(а):
2019.10.05, 13:11
Не слишком ли завышены ожидания на юнит-тесты в целях контроля качества если учесть что в той же литературе указаны относительно не высокие показатели обнаружение ошибок посредством тестирования в сравнение с той же инспекцией кода?
Мой сайт долго был на Yii 1.1.17. В октябре я его обновил на Yii 1.1.20 и переключил на PHP 7.1. Он остался рабочим? Вроде да, так как в логах ошибок не появилось. Но через неделю я случайно обнаружил, что при обновлении поста слетает подсветка PHP-кода в <pre></pre>.

После ковыряний в исходниках я нашёл, что в новом TextHighlighter здесь поменялась регулярка:

Код: Выделить всё

- start="(\&lt;\?(php|=)?)?"
+ start="\&lt;\?(php|=)?" end="\?\>"
Теперь указание "<?php" в начале перестало быть необязательным, и в теге <pre> теперь подсвечивается только код, начинающийся c "<?php ".

Чтобы не проверять всё вручную я написал простейший тест проверки работы конвертера:

Код: Выделить всё

class TextProcessorTest extends TestCase
{
    public function testText()
    {
        $source = <<<END
Lorem ipsum dolor sit amet.

~~~
[php]
interface A extends B
{}
~~~
END;

        $expected = <<<END
<p>Lorem ipsum dolor sit amet.</p>
<div class="hl-code"><div class="php-hl-main"><pre><span class="php-hl-reserved">interface</span> <span class="php-hl-identifier">A</span> <span class="php-hl-reserved">extends</span> <span class="php-hl-identifier">B</span>
<span class="php-hl-brackets">{</span><span class="php-hl-brackets">}</span></pre></div></div>

END;

        $processor = new TextProcessor();
        $result = $processor->process($source);
        $this->assertEquals($expected, $result);
    }
}
и под него доработал код TextProcessor так, чтобы он специально подставлял "<?php" в начало листинга, вызывал CMarkdownParser и потом из начала обратно удалял. Тест показал, что теперь всё работает.

Если приложение написать один раз, проверить и забросить, то оно так и останется рабочим. Но в реальности постоянно обновляется фреймворк и библиотеки и постоянно вносятся правки в сам код.

У меня есть желание переписать сайт с Yii1 на Yii2 или Slim. И теперь имея этот тест мне будет спокойнее и быстрее переписывать. Теперь у меня есть реальная гарантия, что преобразование текста "можно назвать рабочим".

Инспекция кода найдёт только технические ошибки, но не найдёт логические, когда где-то в условии стоит ">" вместо ">=" или где-то в формуле неверно расставлены скобки. Вручную мало кто всё прокликивает, так что это удобнее и надёжнее проверить тестами.
Последний раз редактировалось ElisDN 2019.10.05, 20:21, всего редактировалось 1 раз.

Аватара пользователя
ElisDN
Сообщения: 5452
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение ElisDN » 2019.10.05, 17:45

Wizard писал(а):
2019.10.05, 13:11
Не смотря на то что по каждому из пунктов можно найти отдельную литературу, когда я пишу юнит-тесты какие характеристики я покрываю?
Удобство сопровождения (легко обновлять и рефакторить при наличии тестов)
Портируемость (могу переписать TextProcessor на использование другой библиотеки подсветки)
Возможность повторного использования (слабосвязанный протестированный код легче извлечь из проекта на Packagist)
Удобочитаемость (при продумывании теста мы придумаюи более подходящее имя класса и метода)
Тестируемость (стопроцентная, так как тест уже готов)
Понятность (как и удобочитаемость + классы получаются маленькими и простыми с одной ответственностью)

noLogicOnlyWar
Сообщения: 83
Зарегистрирован: 2017.07.04, 20:53

Re: Пример чистой архитектуры на оценку

Сообщение noLogicOnlyWar » 2019.10.05, 19:45

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


Юнит тесты только часть пирамиды тестов которая строится для контроля качества. Юнит тесты это хорошо, но только их явно не достаточно.
Но вернемся к качеству - чем оно гарантированно зная только о том что у нас есть юнит-тесты? По прежнему приложение можно назвать рабочим
И даже то что приложение рабочее юнит тесты не гарантируют.

uEhlO4a
Сообщения: 68
Зарегистрирован: 2017.08.12, 19:19

Re: Пример чистой архитектуры на оценку

Сообщение uEhlO4a » 2019.10.07, 20:10

maleks
твой пример хреновый, т.к. он не рабочий в принципе

а если по сути, то пишешь в google.com "The Clean Architecture example php project", получаешь пример https://github.com/eminetto/clean-architecture-php - там вроде то что тебе нужно

это вроде даже круче первого примера https://github.com/lezhnev74/ema (https://lessthan12ms.com/clean-architec ... a-php-app/)

Аватара пользователя
maleks
Сообщения: 1827
Зарегистрирован: 2012.12.26, 12:56

Re: Пример чистой архитектуры на оценку

Сообщение maleks » 2019.10.08, 07:05

uEhlO4a писал(а):
2019.10.07, 20:10
maleks
твой пример хреновый, т.к. он не рабочий в принципе

а если по сути, то пишешь в google.com "The Clean Architecture example php project", получаешь пример https://github.com/eminetto/clean-architecture-php - там вроде то что тебе нужно

это вроде даже круче первого примера https://github.com/lezhnev74/ema (https://lessthan12ms.com/clean-architec ... a-php-app/)
Пример рабочий, т.к. это не псевдокод, а реальный функционал, проверенный в работе. Модуль сам подключили? бутстрап, миграции не забыли?

Насчет ваших ссылок из гугла, ну так мое на первый вариант как раз и походит, а те что "покруче" они и позаковыристей в понимании, да и доктрину юзает, как минимум один из них. У меня цель то не просто на php, а на yii все таки, не теоретизирование...
Yii2 universal module sceleton - for basic and advanced templates

uEhlO4a
Сообщения: 68
Зарегистрирован: 2017.08.12, 19:19

Re: Пример чистой архитектуры на оценку

Сообщение uEhlO4a » 2019.10.08, 08:07

ну, я увидел только папку "common", что дальше делать я хз

насчет yii2 - ну я не понимаю зачем ты там тогда используешь ActiveRecord с Repository, который по сути Active часть от Record. У тебя получается ActiveActiveRecord

Аватара пользователя
maleks
Сообщения: 1827
Зарегистрирован: 2012.12.26, 12:56

Re: Пример чистой архитектуры на оценку

Сообщение maleks » 2019.10.08, 08:27

uEhlO4a писал(а):
2019.10.08, 08:07
1)ну, я увидел только папку "common", что дальше делать я хз

2)насчет yii2 - ну я не понимаю зачем ты там тогда используешь ActiveRecord с Repository, который по сути Active часть от Record. У тебя получается ActiveActiveRecord
1) Там в common обычный модуль просто лежит, а common потому что advanced шаблон.
2) С чего вы взяли что Active часть от ActiveRecord - это Repository? Тогда уж Record часть.
Для чего репозиторий я говорил выше, чтобы на внутренних слоях - юзкейсах и сущностях - никогда не думать в терминах базы данных, грубо говоря $ar->save() там не вызывать
Yii2 universal module sceleton - for basic and advanced templates

uEhlO4a
Сообщения: 68
Зарегистрирован: 2017.08.12, 19:19

Re: Пример чистой архитектуры на оценку

Сообщение uEhlO4a » 2019.10.08, 08:46

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

насчет Active - то репозиторий, это именно Active часть, т.к. отвечает за работу с базой, просто собирая запросы, ничего более. сохранение одной записи - это частный случай. / http://web.archive.org/web/201504041542 ... le-csharp/

" никогда не думать в терминах базы данных" - я не понял этот момент. у тебя есть обьект который может делать save(), о чем я не должен думать? я прихожу и тупо вызываю $post->save() потому что могу, да ты и сам это делаешь, только название методов почему-то поменял.

Аватара пользователя
ElisDN
Сообщения: 5452
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Пример чистой архитектуры на оценку

Сообщение ElisDN » 2019.10.08, 08:59

uEhlO4a писал(а):
2019.10.08, 08:46
правлом хорошего тона является файл readme.md с текстом вроде "нажми сюда - будет хорошо", ладно, проехали, не судьба значит это мне запустить.
Также запускается, как и другие проекты и модули на Yii2.
uEhlO4a писал(а):
2019.10.08, 08:46
насчет Active - то репозиторий, это именно Active часть, т.к. отвечает за работу с базой, просто собирая запросы, ничего более. сохранение одной записи - это частный случай.
Можете это нам из определения процитировать?

Аватара пользователя
maleks
Сообщения: 1827
Зарегистрирован: 2012.12.26, 12:56

Re: Пример чистой архитектуры на оценку

Сообщение maleks » 2019.10.08, 09:03

uEhlO4a писал(а):
2019.10.08, 08:46
насчет Active - то репозиторий, это именно Active часть, т.к. отвечает за работу с базой, просто собирая запросы, ничего более. сохранение одной записи - это частный случай. / http://web.archive.org/web/201504041542 ... le-csharp/
An object carries both data and behavior
Active - behavior, Record - data
uEhlO4a писал(а):
2019.10.08, 08:46
" никогда не думать в терминах базы данных" - я не понял этот момент. у тебя есть обьект который может делать save(), о чем я не должен думать? я прихожу и тупо вызываю $post->save() потому что могу, да ты и сам это делаешь, только название методов почему-то поменял.
Ну вот в этом и разница, раньше "тупо" вызывался save() где хочется, а теперь объекту будет просто меняться состояние в памяти, а детали сохранения реализует репозиторий. Как в схеме этой архитектуры.
Ну этот момент вообще то чисто для пробы, гляну как там на практике удобно будет получаться
Yii2 universal module sceleton - for basic and advanced templates

uEhlO4a
Сообщения: 68
Зарегистрирован: 2017.08.12, 19:19

Re: Пример чистой архитектуры на оценку

Сообщение uEhlO4a » 2019.10.08, 09:17

maleks,
behavior - save() delete() getById() - это что по-твоему?
так что попробуй убрать ActiveRecord и найти решение, чтобы было по этой книжке и засунуть это в Yii2. если получтся, админ тебя в core команду заберет, инфа 100



п.с.
ElisDN, я разводить лохов тебе не мешаю, так что отьеб..сь от меня, ок? админ забанил уже одну тему которая ушла в срач. я пишу maleks а не тебе. следующий твой висер я буду игнорить
"In such systems it can be worthwhile to build another layer of abstraction over the mapping layer where query construction code is concentrated. This becomes more important when there are a large number of domain classes or heavy querying. In these cases particularly, adding this layer helps minimize duplicate query logic."
query - запрос

аминь

Ответить