TGViewer
FastNews | Никита Пастухов FastNews | Никита Пастухов @fastnewsdev · 2.62K subscribers
Post #18 460
Последнее время я часто говорю про какой-то "реекспорт" и меня никто не понимает. Обидно...

Поэтому накидаю свои мысли на этот счет постом, чтобы на него потом ссылаться.

Какие у нас вводные?
1.1) Есть два разных контекста кода, которые схожи друг с другом, но не должны пересекаться по реализации из сообрежений SRP.

ИЛИ

1.2) Есть внешний код, который закрывает нашу потребность (пока что), но в перспективе наши требования могут заставить нас отказаться от этого объекта и спрятать его за свой адаптер.
2) Мы не хотим писать много кода уже сейчас. Поэтому мы не против чуть-чуть накинуть грязи с понятной стратегией ее уборки.

Т.е. у нас есть кусок кода и нам нужно изобрести свой второй пока что такой же (ключевое слово пока что, т.к. таким же он быть не может из-за SRP), но дублировать его мы не хотим (DRY же, да?)

В общем - идея моего "реекспорта" очень простая. Мы делаем все подготовительные действия так, если бы мы писали "правильно" - т.е. создает отдельный модуль под нашу реализация, везде используем импорты на нее, закрываем ее протоколом при необходимости и т.д. Но потом не делаем самое последнее действие - *не пишем свою реализацию*. Или пишем, но частично...

Приведу пример из исходинов FastStream 0.6.0: у нас есть 2 модуля генерации документации

* faststream.specification.asyncapi.v2_6_0
* faststream.specification.asyncapi.v3_0_0

Соответственно, это разные мажорные версии спецификации и даже общие куски между ними представляют собой мнимое дублирование. Т.е. мы не можем создать какой-нибудь shared модуль, куда вынесем общие классы для этих спецификаций. А что делать? Ну, конечно же, заводить полное дерево объектов для каждого из подмодулей. Т.е. v3_0_0 и v2_6_0 модули имеют внутри себя набор всех необходимых для их работы объектов и не могут импортировать какие-то объекты друг из друга.

Но ведь код полностью дублировать не хочется?😉

Ну, поэтому мы просто делаем одинаковые деревья файлов в этих модулях, пишем полную v2_6_0 реализацию, а в v3_0_0 начинаем "лайфхачить"

Например, какой-нибудь v3_0_0.servers.ServerVariable может на уровне реализации выглядеть вот так


from faststream.specification.asyncapi.v2_6_0.schema import ServerVariable

__all__ = (
"ServerVariable",
)


Или какой-нибудь ChannelBinding может наследоваться от своей же версии из v2_6_0


from faststream.specification.asyncapi.v2_6_0.schema.bindings.amqp import (
ChannelBinding as V2Binding,
)

class ChannelBinding(V2Binding): ...


Сами по себе такие приемы нарушают SRP и вообще ай-ай-ай. Т.е. у нас контекст знает об объектах из совершенно другого контекста. И даже выставляет их за свою реализацию! Или наследует! Ужас, в общем.

Но суть в том, что об этом за пределами файла с реализацией никто не знает. Весь остальной код притворяется, что использует полноправную самостоятельную реализацию v3_0_0.bindings.ChannelBinding класса. А это открывает нам возможность маневра по удалению этого нарушения SRP очень простыми способами в дальнейшем (когда оно начнет стрелять нам по ногам)

1) Мы можем патчить и дорабатывать реализацию другого модуля через наследование, о котором никто не узнает
2) Мы можем спрятать реализацию другого модуля за фасад
3) Мы можем удалить "реекспорт"/наследование и написать в файле полностью самостоятельную реализиацию

В общем и целом, никто не знает, что там происходит внутри файла, поэтому никто не узнает, что SRP нарушен, а это значит, что ему это не навредит🌚

Однако, тут есть один подводный камень - если мы "реекспортируем" / наследуемся от реализации из другого контекста, то пользователь нашей реализации может завязаться на те методы, которые пришли из исходной реализации и не предпологаются в API текущей. Тогда, при устранении нарушения SRP мы столкнемся с тем, что часть кода пользователя отваливается из-за несовместимости новой реализации API старой. Поэтому в *идеальном мире* мы должны прятать такие "реекспорты" хотя бы за адаптер. Но на практике это излишне.

#программирование
  • 🔥 3
  • 😁 1
More from @fastnewsdev
  1. Oct 4, 2026Как я учу английский с помощью AI Насколько вы знаете, я большую часть работы веду в OpenS…
  2. Oct 2, 2026Чтож, антропики добрались и до меня и забанили аккант😢 В связи с этим посты ближайшие пар…
  3. Sep 30, 2026Последний месяц на мой канал жестко нападают всякие-разные ИТшницы и ИИшницы, которые поче…
  4. Sep 27, 2026Я уже жаловался на то, что конференции как формат изживают себя. И поэтому мне нравится, ч…
  5. Sep 22, 2026Еще недавно я вайнил, что нейронки нельзя использовать в OpenSource, т.к. они не вывозят т…
  6. Sep 20, 2026Последние 2 недели я заметил, что Opus 5 значительно отупел в Claude Code. Обычно такое сл…
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 →