Как применять loose coupling на практике?

 Публичный пост

Салют, клуб! Есть вопрос из разряда ликбеза, может поможете найти ответ.

Если вкратце, то я не совсем понимаю идею loose coupling в программировании, а точнее ее границы. Ну, то есть я начитался аналогий про машины и компьютеры и что их детали должны быть заменяемы. Есть даже более практические примеры про независимость приложения от конкретной базы данных, например, чтобы прога могла и с PostgreSQL работать и с MySQL.

А теперь вот собственно и вопрос: до какой степени стоит доводить это самое loose coupling (мы же не ситхи)? То есть мы живем в век постмодерна, где все за нас придумали. И есть куча либ, которые сами инкапсулируют конкретную реализацию той же базы данных, а наружу выдают абстрактные репозитории, где с точки зрения программиста “select” и в Африке PostgreSQL select и в MySQL. Но при этом появляется жесткая зависимость программы от самой либы, есть ли в этом проблема? Должен ли я как кодер делать свою программу не только агностиком в плане базы данных, но и в плане либы для работы с базами данных?

Помимо этого, правильно ли я понимаю, что loose coupling предполагает принесение в жертву преимуществ конкретной реализации? Тут примером будет уже фронт (так как это более знакомая мне тема). Допустим я задумал сделать свой фронт независимым от REST+RSQL/GraphQL, написал абстрактный универсальный сервис и пару имплементаций под каждую из опций. Но ведь теперь я ограничен в гибкости, так как в графе из коробки куда больше фишек (кэш, вэбсокеты и так далее). И выхода получается два: или ручками реализовывать недостающее в одной из реализаций, чтобы выровнять ее с другой, или ограничиться тем меньшим функционалом, который из коробки есть и там и там, верно?

4 комментария 👇
Миша Гусаров, Инженегр-погромист 1 июня в 07:15

Loose coupling между слоями — это частный случай, я бы рассмотрел более общо.

Loose coupling — это отсутствие tight coupling. Tight coupling — это состояние дизайна, при котором структура одной части зависит от неинтересных этой части деталей другой.

К примеру:
— просачивающиеся через границы модулей детали реализации (mongodb.UINT какой-нибудь в интерфейсе, которым пользуется бизнес-логика);
— структурирование модуля под стиль управления в другом модуле (callbacks и promises из-за того, что другой модуль их использует);
— неявные зависимости по времени (обязательный сброс watchdog с помощью теребления какой-либо функции используемого модуля).

С этим стоит бороться, так как это часто мешает. Языки могут либо помогать, либо мешать в этом. К примеру, Go помогает переходить между синхронными/асинхронными интерфейсами с помощью дешёвых корутин, но никак не помогает справляться с просачиванием типов.

Но при этом появляется жесткая зависимость программы от самой либы, есть ли в этом проблема? Должен ли я как кодер делать свою программу не только агностиком в плане базы данных, но и в плане либы для работы с базами данных?

Это обычная архитектурная работа: насколько зависимость (база данных, библиотека, внешний сервис) подходит, и какие есть требования или ожидания, что придётся отказаться.

Обычно решается не на уровне ORM, а на следующем: если в интерфейсе func Customer(id string) (*Customer, error), то неважно, что внутри: чистый Oracle SQL, какой-то ORM или поднятый JSON с диска.

Но это не loose coupling, это обычный полиморфизм (compile-time или run-time) и выбор деталей реализации.

  Развернуть 1 комментарий

Лучше один раз увидеть, чем 100 раз услышать:

Tight coupling — много связей между модулями, входные потоки попадают в несколько модулей, выходные также из нескольких модулей. Модуль «обрастает» корнями так, что не выдрать. Или это потребует очень кропотливой работы по учёту всех связей (но про одну всегда забудете).

Loose coupling —С внешним миром на вход взаимодействует один модуль, на выход другой. Паразитных связей нет. Если связи между модулями не описаны, то сделать это будет проще.

И никакого шаманства.

Причем нет тождества, что loose — хорошо, а tight — плохо. It depends.

  Развернуть 1 комментарий

А теперь вот собственно и вопрос: до какой степени стоит доводить это самое loose coupling (мы же не ситхи)?

Я рассматриваю слабое связывание как фичу, такую же как и остальные. Она дает как приемущество - несложно будет что-то менять что-то слабосвязанное, так и недостатки - нужно написать/использовать дополнительные обертки, код будет более сложным, абстракции где-то протекут через обертки и будет неприятно.

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

Тут правда еще нужно понять что за проект. Если это рельсы, где уже есть ORM выкидывать его - это больше зло, нежли упрощение.

Помимо этого, правильно ли я понимаю, что loose coupling предполагает принесение в жертву преимуществ конкретной реализации?

Правильно. Чем выше адаптируемость к различным условиям, тем ниже приспособленность к конкретным условиям существования (с) Дарвин.

  Развернуть 1 комментарий

Ну четких критериев, которые можно померять нет. Т.к все эти принципы это шаманизм в чистом виде, то надо смотреть на практику.

Там где tight coupling может быть вреден: зависимость от базы, когда концепции чтения и записи данных проникают в логику, зависимость внутренних типов и API какой-нибудь внешней библиотеки, зависимость кодовых баз двух модулей, которые деплоятся раздельно; также связность двух относительно больших модулей вредящая понимаю и чтению кода (субъективно, да); зависимость логики и сценариев от мелких технических деталей и инфраструктурного кода.

Вот там где это все мешает, и надо разрывать зависимости и скрывать детали под интерфейсы, объединять близкое по смыслу, итд....

  Развернуть 1 комментарий

😎

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

Что вообще здесь происходит?


Войти  или  Вступить в Клуб