Информация об изменениях

Сообщение Re: Дизайн разделения бизнес-слоя (логического) на два уровн от 23.05.2024 8:00

Изменено 23.05.2024 8:05 vsb

Re: Дизайн разделения бизнес-слоя (логического) на два уровн
Лично я считаю немного по-другому. Тут немного абстрактно опишу, извиняюсь заранее.

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

Теперь вернёмся к делению и группировки кода. В конечном итоге у нас имеется код на каком-то языке программирования, состоящий из строк. Эти строки объединяются в функции, функции могут объединяться в классы и тд. Какие-то строки будут расположены рядом. К примеру методы одного класса обычно будут в одном файле. Может быть даже идти друг за другом. Какие-то строки будут далеко друг от друга. К примеру один сервис вызывает другой. Код, который вызывает через HTTP Client, формирует запрос и тд находится в одном репозитории, код, который обрабатывает этот запрос — находится в другом репозитории.

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

И вот теперь приходим к оценке архитектуры. Мой главный принцип — при реализации изменений в ТЗ, код должен меняться как можно более локально. Т.е. приходит требование, мы его реализуем и в идеале код меняется в одной функции. Или в одном классе. Или в одном пакете. Или хотя бы в одном сервисе.

Если для реализации задачи нам часто требуется бегать по всей программе, архитектура плохая.

С этой формализацией качества архитектуры я и предпочитаю работать. И поэтому первое правило — это использование features как основного принципа деления кода. Т.е. код в первейшую очередь делится не на слои, а на фичи. Т.к. чаще всего при последующих доработках задачи будут локальными в пределах одной фичи.

Теперь что касается слоёв. Вообще слои зависят от используемых фреймворков. К примеру если мы работаем с SQL, без ORM, слой для доступа к БД весьма желателен. Ну сложно без него, каша будет. Но этот слой опять же вполне может быть прямо внутри фичи. А где-то можно и без него обойтись, если код простой. Усложнить всегда успеем, extract to method есть в любой IDE. А начинать надо с простого кода, даже если там смешиваются концепции, ничего страшного. Куда хуже писать hello world в enterprise стиле. А если мы работаем с ORM, то вполне можно посчитать, что код ORM это уже и есть наш Data Abstraction Layer. И городить ещё один, в котором методы будут состоять в основном из одного вызова соответствующего метода ORM, это привнесение сложности на ровном месте.

Также хочу ещё заметить, что считаю весьма полезным максимальную изоляцию интерфейсов между компонентами в любом виде. Вот как иногда делают — сделали Entity-класс, отражающий таблицу из БД, навесили на него аннотаций, а потом берут и его же в JSON и отдают фронту. Вот это плохо. Правильно сделать пусть даже на сегодня полную копию этого класса, но отдельную. Да, придётся немножко boilerplate кода написать, копирующего одно в другое, ничего страшного. Если сильно противно — можно автоматизировать. Но связь между backend и frontend должна быть независимой от связи между backend и database. А если вы уверены, что она не должна быть независимой, зачем вы вообще пишете код, возьмите PostgREST.

И ещё хочу заметить, что имею твёрдое мнение, что многие т.н. best practices на деле являются вредными. Поэтому настоятельно рекомендую формировать в голове свой понятийный аппарат и максимально его формализовать. Если кто-то пишет, как надо лучше, то нужно пытаться разобраться — а почему так надо? А чем измеряетя это "лучше"? Вот говорят — надо убирать дублирующийся код в отдельные функции. А почему надо? А может не надо? А может лучше не убирать? А может в каких-то случаях лучше оставлять дублирующийся код? А почему вообще этот человек мне пытаетя указывать, как писать код? Зачем он эту книгу написал? Начинаешь копать и оказывается, что сам он особо ничего сверхъестественного и не написал, а работает консультантом, по сути пытается учить других писать код по своей книжке. А те, кто пишет действительно сложные системы, они чаще всего книжки и не пишут, они молча сидят где-то в недрах корпораций и про них толком никто и не знает кроме тех, кто с ними работает.

Однозначное правило только одно — однозначных правил нет. Всегда и везде есть плюсы и минусы. Как говорится — there's no silver bullet. Поэтому спрашивать про правильную архитектуру в отрыве от конкретной задачи — смысла просто нет.
Re: Дизайн разделения бизнес-слоя (логического) на два уровн
Лично я считаю немного по-другому. Тут немного абстрактно опишу, извиняюсь заранее.

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

Теперь вернёмся к делению и группировки кода. В конечном итоге у нас имеется код на каком-то языке программирования, состоящий из строк. Эти строки объединяются в функции, функции могут объединяться в классы и тд. Какие-то строки будут расположены рядом. К примеру методы одного класса обычно будут в одном файле. Может быть даже идти друг за другом. Какие-то строки будут далеко друг от друга. К примеру один сервис вызывает другой. Код, который вызывает через HTTP Client, формирует запрос и тд находится в одном репозитории, код, который обрабатывает этот запрос — находится в другом репозитории.

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

И вот теперь приходим к оценке архитектуры. Мой главный принцип — при реализации изменений в ТЗ, код должен меняться как можно более локально. Т.е. приходит требование, мы его реализуем и в идеале код меняется в одной функции. Или в одном классе. Или в одном пакете. Или хотя бы в одном сервисе.

Если для реализации задачи нам часто требуется бегать по всей программе, архитектура плохая.

С этой формализацией качества архитектуры я и предпочитаю работать. И поэтому первое правило — это использование features как основного принципа деления кода. Т.е. код в первейшую очередь делится не на слои, а на фичи. Т.к. чаще всего при последующих доработках задачи будут локальными в пределах одной фичи.

Теперь что касается слоёв. Вообще слои зависят от используемых фреймворков. К примеру если мы работаем с SQL, без ORM, слой для доступа к БД весьма желателен. Ну сложно без него, каша будет. Но этот слой опять же вполне может быть прямо внутри фичи. А где-то можно и без него обойтись, если код простой. Усложнить всегда успеем, extract to method есть в любой IDE. А начинать надо с простого кода, даже если там смешиваются концепции, ничего страшного. Куда хуже писать hello world в enterprise стиле. А если мы работаем с ORM, то вполне можно посчитать, что код ORM это уже и есть наш Data Abstraction Layer. И городить ещё один, в котором методы будут состоять в основном из одного вызова соответствующего метода ORM, это привнесение сложности на ровном месте.

Также хочу ещё заметить, что считаю весьма полезным максимальную изоляцию интерфейсов между компонентами в любом виде. Вот как иногда делают — сделали Entity-класс, отражающий таблицу из БД, навесили на него аннотаций, а потом берут и его же в JSON и отдают фронту. Вот это плохо. Правильно сделать пусть даже на сегодня полную копию этого класса, но отдельную. Да, придётся немножко boilerplate кода написать, копирующего одно в другое, ничего страшного. Если сильно противно — можно автоматизировать. Но связь между backend и frontend должна быть независимой от связи между backend и database. А если вы уверены, что она не должна быть независимой, зачем вы вообще пишете код, возьмите PostgREST.

И ещё хочу заметить, что имею твёрдое мнение, что многие т.н. best practices на деле являются вредными. Поэтому настоятельно рекомендую формировать в голове свой понятийный аппарат и максимально его формализовать. Если кто-то пишет, как надо лучше, то нужно пытаться разобраться — а почему так надо? А чем измеряется это "лучше"? Вот говорят — надо убирать дублирующийся код в отдельные функции. А почему надо? А может не надо? А может лучше не убирать? А может в каких-то случаях лучше оставлять дублирующийся код? А почему вообще этот человек мне пытается указывать, как писать код? Зачем он эту книгу написал? Начинаешь копать и оказывается, что сам он особо ничего сверхъестественного и не написал, а работает консультантом, по сути пытается учить других писать код по своей книжке. А те, кто пишет действительно сложные системы, они чаще всего книжки и не пишут, они молча сидят где-то в недрах корпораций и про них толком никто и не знает кроме тех, кто с ними работает.

Однозначное правило только одно — однозначных правил нет. Всегда и везде есть плюсы и минусы. Как говорится — there's no silver bullet. Поэтому спрашивать про правильную архитектуру в отрыве от конкретной задачи — смысла просто нет.