Владельцу не нравится множество объектов, создаваемых прямым new в коде. Паттерн: есть логика
(реализация фабрики) и интерфейс фабрики, который возвращает интерфейс готового объекта.
Если объект собирается итеративно (много частей/опций) — добавляется билдер. DTO не касаемся: у них нет интерфейсов, они создаются по месту и не меняются. Статичные хэлперы не трогаем (уточнение владельца): обычно хэлперы — статичные классы, фабрики для них не заводим.
Что сделать
Инвентаризация: места создания нетривиальных объектов через new (сервисы/хелперы/компоненты, не DTO).
Для каждой группы — фабрика: IXxxFactory + XxxFactory, метод возвращает интерфейс готового объекта.
Для итеративно собираемых объектов — билдер (IXxxBuilder/XxxBuilder), фабрика делегирует билдеру.
Перевести места создания на фабрики; прямые new реализаций убрать (остаются только внутри фабрик).
Критерии приёмки
вне фабрик нет new нетривиальных объектов (кроме DTO/исключений/примитивов)
сборка 5 решений 0/0, тесты зелёные
правила зафиксированы в код-стайле
Затрагивает
core (сервисы, инфраструктура), тесты; фронт не трогаем
Источники
Запрос владельца 2026-09-12
## Контекст
Владельцу не нравится множество объектов, создаваемых прямым `new` в коде. Паттерн: есть логика
(реализация фабрики) и **интерфейс фабрики**, который возвращает **интерфейс готового объекта**.
Если объект собирается итеративно (много частей/опций) — добавляется **билдер**.
**DTO не касаемся**: у них нет интерфейсов, они создаются по месту и не меняются.
**Статичные хэлперы не трогаем** (уточнение владельца): обычно хэлперы — статичные классы, фабрики для них не заводим.
## Что сделать
1. Инвентаризация: места создания нетривиальных объектов через `new` (сервисы/хелперы/компоненты, не DTO).
2. Для каждой группы — фабрика: `IXxxFactory` + `XxxFactory`, метод возвращает интерфейс готового объекта.
3. Для итеративно собираемых объектов — билдер (`IXxxBuilder`/`XxxBuilder`), фабрика делегирует билдеру.
4. Перевести места создания на фабрики; прямые `new` реализаций убрать (остаются только внутри фабрик).
## Критерии приёмки
- [x] вне фабрик нет `new` нетривиальных объектов (кроме DTO/исключений/примитивов)
- [x] сборка 5 решений 0/0, тесты зелёные
- [x] правила зафиксированы в код-стайле
## Затрагивает
- core (сервисы, инфраструктура), тесты; фронт не трогаем
## Источники
- Запрос владельца 2026-09-12
Принято: статичные хэлперы (static class) не трогаем — фабрики только для нетривиальных объектов с интерфейсами. Описание задачи уточнено. Возьму в работу после закрытия задачи #1 (NSubstitute).
Принято: статичные хэлперы (static class) не трогаем — фабрики только для нетривиальных объектов с интерфейсами. Описание задачи уточнено. Возьму в работу после закрытия задачи #1 (NSubstitute).
Регистраторы (AddDealPersistence/AddDealIntegrations/AddDealSecurity, AddDealFileStorage) и DiscoveryWorkerService больше не создают реализации напрямую; счётчик ошибок поиска стал обязательной зависимостью.
Правило фабрик/билдеров и список исключений зафиксированы в код-стайле (§4.1).
Тест FileStorageFactory (Local/MinIO).
Проверки: сборка 5 решений 0/0; тесты core 1342, telegram 130, ai 52, ml 38, storage 9.
Область/исключения (прямой new без порт-интерфейса или не прикладной объект):
EF-конфигурации (IEntityTypeConfiguration, modelBuilder.ApplyConfiguration(new X())) — метаданные модели EF, а не прикладные объекты;
gRPC-соединения Ai/Ml/TelegramGrpcConnection — обёртки ресурсов с IDisposable без порт-интерфейса;
статичные хэлперы и объекты без порт-интерфейса, создаваемые контейнером (AddScoped<Concrete>()).
Открытый вопрос: считать ли EF-конфигурации объектами под это правило? Если да — переведу оба контекста на ApplyConfigurationsFromAssembly (потребует разделения namespace конфигураций).
Билдеры в текущем объёме не потребовались: все целевые объекты собираются одним конструктором с DI-зависимостями (не итеративно). Правило для билдеров зафиксировано в код-стайле на будущее.
Реализовано:
- Фабрики: `ISecretCipherFactory`, `ITenantLimitStoreFactory`, `IAiClassifierFactory`, `IAiToolsFactory`, `IFileStorageFactory` (+ `LocalStorageRoot`).
- Регистраторы (`AddDealPersistence`/`AddDealIntegrations`/`AddDealSecurity`, `AddDealFileStorage`) и `DiscoveryWorkerService` больше не создают реализации напрямую; счётчик ошибок поиска стал обязательной зависимостью.
- Правило фабрик/билдеров и список исключений зафиксированы в код-стайле (§4.1).
- Тест `FileStorageFactory` (Local/MinIO).
Проверки: сборка 5 решений 0/0; тесты core 1342, telegram 130, ai 52, ml 38, storage 9.
Область/исключения (прямой `new` без порт-интерфейса или не прикладной объект):
- EF-конфигурации (`IEntityTypeConfiguration`, `modelBuilder.ApplyConfiguration(new X())`) — метаданные модели EF, а не прикладные объекты;
- gRPC-соединения `Ai/Ml/TelegramGrpcConnection` — обёртки ресурсов с `IDisposable` без порт-интерфейса;
- статичные хэлперы и объекты без порт-интерфейса, создаваемые контейнером (`AddScoped<Concrete>()`).
Открытый вопрос: считать ли EF-конфигурации объектами под это правило? Если да — переведу оба контекста на `ApplyConfigurationsFromAssembly` (потребует разделения namespace конфигураций).
Билдеры в текущем объёме не потребовались: все целевые объекты собираются одним конструктором с DI-зависимостями (не итеративно). Правило для билдеров зафиксировано в код-стайле на будущее.
Причина флейков: TelegramIngressTestHost мутировал процессную переменную DEAL_SERVICE_TOKEN, а три ingress-тест-класса (IngressRateLimitInterceptorTests, TelegramIngressServiceTests, SourceIngressGrpcServiceTests) идут параллельно и перетирали значение друг другу (сервер читал чужой токен → не тот код ответа).
Фикс: токен задаётся in-memory конфигурацией хоста (builder.Configuration.AddInMemoryCollection), глобальный env больше не трогается. IngressServiceTokenInterceptor читает токен из конфигурации, поэтому поведение прод-кода не менялось.
Проверка: 18 прогонов полного набора подряд — все зелёные (ранее падало ~1 из 3).
Стабильность тестов исправлена (коммит в MR #14).
Причина флейков: `TelegramIngressTestHost` мутировал процессную переменную `DEAL_SERVICE_TOKEN`, а три ingress-тест-класса (`IngressRateLimitInterceptorTests`, `TelegramIngressServiceTests`, `SourceIngressGrpcServiceTests`) идут параллельно и перетирали значение друг другу (сервер читал чужой токен → не тот код ответа).
Фикс: токен задаётся in-memory конфигурацией хоста (`builder.Configuration.AddInMemoryCollection`), глобальный env больше не трогается. `IngressServiceTokenInterceptor` читает токен из конфигурации, поэтому поведение прод-кода не менялось.
Проверка: 18 прогонов полного набора подряд — все зелёные (ранее падало ~1 из 3).
Исправлено замечание владельца по код-стайлу: метод Create фабрик теперь реализован явно (ISecretCipher ISecretCipherFactory.Create()), интерфейс вызывается только по порту, дублей summary нет. Аудит правила по всему проекту — задача #15.
Исправлено замечание владельца по код-стайлу: метод Create фабрик теперь реализован явно (ISecretCipher ISecretCipherFactory.Create()), интерфейс вызывается только по порту, дублей summary нет. Аудит правила по всему проекту — задача #15.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Контекст
Владельцу не нравится множество объектов, создаваемых прямым
newв коде. Паттерн: есть логика(реализация фабрики) и интерфейс фабрики, который возвращает интерфейс готового объекта.
Если объект собирается итеративно (много частей/опций) — добавляется билдер.
DTO не касаемся: у них нет интерфейсов, они создаются по месту и не меняются.
Статичные хэлперы не трогаем (уточнение владельца): обычно хэлперы — статичные классы, фабрики для них не заводим.
Что сделать
new(сервисы/хелперы/компоненты, не DTO).IXxxFactory+XxxFactory, метод возвращает интерфейс готового объекта.IXxxBuilder/XxxBuilder), фабрика делегирует билдеру.newреализаций убрать (остаются только внутри фабрик).Критерии приёмки
newнетривиальных объектов (кроме DTO/исключений/примитивов)Затрагивает
Источники
В описании неточности, обычно хэлперы это статичные классы, их мы не трогаем
Принято: статичные хэлперы (static class) не трогаем — фабрики только для нетривиальных объектов с интерфейсами. Описание задачи уточнено. Возьму в работу после закрытия задачи #1 (NSubstitute).
Беру в работу: инвентаризация
newи фабрики для нетривиальных объектов с интерфейсами.Реализовано:
ISecretCipherFactory,ITenantLimitStoreFactory,IAiClassifierFactory,IAiToolsFactory,IFileStorageFactory(+LocalStorageRoot).AddDealPersistence/AddDealIntegrations/AddDealSecurity,AddDealFileStorage) иDiscoveryWorkerServiceбольше не создают реализации напрямую; счётчик ошибок поиска стал обязательной зависимостью.FileStorageFactory(Local/MinIO).Проверки: сборка 5 решений 0/0; тесты core 1342, telegram 130, ai 52, ml 38, storage 9.
Область/исключения (прямой
newбез порт-интерфейса или не прикладной объект):IEntityTypeConfiguration,modelBuilder.ApplyConfiguration(new X())) — метаданные модели EF, а не прикладные объекты;Ai/Ml/TelegramGrpcConnection— обёртки ресурсов сIDisposableбез порт-интерфейса;AddScoped<Concrete>()).Открытый вопрос: считать ли EF-конфигурации объектами под это правило? Если да — переведу оба контекста на
ApplyConfigurationsFromAssembly(потребует разделения namespace конфигураций).Билдеры в текущем объёме не потребовались: все целевые объекты собираются одним конструктором с DI-зависимостями (не итеративно). Правило для билдеров зафиксировано в код-стайле на будущее.
MR: #14
Стабильность тестов исправлена (коммит в MR #14).
Причина флейков:
TelegramIngressTestHostмутировал процессную переменнуюDEAL_SERVICE_TOKEN, а три ingress-тест-класса (IngressRateLimitInterceptorTests,TelegramIngressServiceTests,SourceIngressGrpcServiceTests) идут параллельно и перетирали значение друг другу (сервер читал чужой токен → не тот код ответа).Фикс: токен задаётся in-memory конфигурацией хоста (
builder.Configuration.AddInMemoryCollection), глобальный env больше не трогается.IngressServiceTokenInterceptorчитает токен из конфигурации, поэтому поведение прод-кода не менялось.Проверка: 18 прогонов полного набора подряд — все зелёные (ранее падало ~1 из 3).
Исправлено замечание владельца по код-стайлу: метод Create фабрик теперь реализован явно (ISecretCipher ISecretCipherFactory.Create()), интерфейс вызывается только по порту, дублей summary нет. Аудит правила по всему проекту — задача #15.