Нарушение принципов SOLID и другое
Задача:
В таблице RawLinks [ID,Link]
скапливаюься необработанные (с мусором) ссылки на подобии этой 325230fkewf ru.stackoverflow.com/users/373567/ odwf3430
. Необходимо определять их тип, нормализовать в соответствии с типоп, проверять по базе уже существующих ссылок, если нет, сохранить.
Cамо решение задачи не интересует, она решается и так и сяк.
Нужна помощь с выделением сущности, с принципами SOLID
Загвоздка в понимании как лучше:
- Нужно использовать 1 какую то сущность сохраняя её состоянии по разным таблицам ?
- Или может быть нужно иметь объекты под все ситуации, типа
RawLink
,DefinedLink
,NotDefinedLinks
и т.д. - Или может сущность и DTO
- Или вообще всё как то иначе
Код 1 из 3 подобных микро компонентов
public class StackOverflowLink
{
public string Link { get; set; }
}
public class TypedStackOverflowLink : StackOverflowLink
{
public TypeStackOverflowLink Type { get; set; }
}
public class Definer(IDataSource<StackOverflowLink> dataSourceRawLink, IDataReceiver<TypedStackOverflowLink> dataReceiverDefinedLink, IDataReceiver<StackOverflowLink> dataReceiverNotDefinedLink)
{
public async Task StartAsync()
{
while (true)
{
try
{
await UnitWorkAsync();
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
await Task.Delay(1000);
}
}
// Открыт для интеграционного теста
public async Task UnitWorkAsync()
{
StackOverflowLink rawLink = await WaitGetRawLinkAsync();
TypeStackOverflowLink typeStackOverflowLink = DefineType(rawLink);
await WaitReceiveAsync(typeStackOverflowLink, rawLink);
}
private async Task<StackOverflowLink> WaitGetRawLinkAsync()
{
while (true)
{
try
{
StackOverflowLink? rawLink = await dataSourceRawLink.GetAsync();
if (rawLink != null)
{
return rawLink;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
await Task.Delay(1000);
}
}
private async Task WaitReceiveAsync(TypeStackOverflowLink typeStackOverflowLink, StackOverflowLink rawLink)
{
while (true)
{
try
{
switch (typeStackOverflowLink)
{
case TypeStackOverflowLink.User:
case TypeStackOverflowLink.Question:
await dataReceiverDefinedLink.ReceiveAsync(new TypedStackOverflowLink()
{
Link = rawLink.Link,
Type = typeStackOverflowLink
});
break;
case TypeStackOverflowLink.Unknown:
await dataReceiverNotDefinedLink.ReceiveAsync(rawLink);
break;
case TypeStackOverflowLink.None:
default:
throw new ArgumentException($"Неожиданный тип enum typeStackOverflowLink = {typeStackOverflowLink}");
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
}
}
private TypeStackOverflowLink DefineType(StackOverflowLink stackOverflowLink)
{
if (Regex.IsMatch(stackOverflowLink.Link, @"ru\.stackoverflow\.com/questions/\d+/"))
{
return TypeStackOverflowLink.Question;
}
else if (Regex.IsMatch(stackOverflowLink.Link, @"ru\.stackoverflow\.com/users/\d+/"))
{
return TypeStackOverflowLink.User;
}
else
{
return TypeStackOverflowLink.Unknown;
}
}
}
PS. Хотел написать вопрос касально проекта из связки независимо работающих 3х компонентов, но он через чур громоздкий для поста( и такое наверно даже никто не прочитает, поэтому попробую по чуть чуть.
Ответы (1 шт):
Скорее всего вы имели в виду принцип "single responsibility" из SOLID
. Но вообще тут скорее нужно исходить из того, как оптимально спроектировать БД под эту задачу. Если я правильно понимаю, если отсеять всю шелуху, у вас есть исходные сырые ссылки и почищенные, проверенные, типизированные чистые ссылки. Ну вот я бы и сделал две таблицы в БД, условно назовём:
- RawLinks
- TypedLinks
В первой таблице как сами сырые ссылки, так и необходимые данные для работы задачи по очистке ссылок. Фактически, это таблица задач.
Во второй таблице - результат чистки. С отсылкой к первой таблице - из чего это у нас такая ссылочка получилась, из какого мусора.
Зачем именно две таблицы. Просто чтобы задачи, которые работают с чистыми ссылками быстрее читали данные. Как вариант, вторая таблица может быть "витриной" или копией "очищенной" ссылки, лежащей в первой таблице. Тут нужно смотреть - кто у вас этими "очищенными" ссылками пользуется и насколько ему критична скорость чтения из БД, нужна ли вообще тут эта оптимизация с разбивкой на две таблицы.
С первой же таблицей всё понятно. Единая таблица из обработанных и ещё необработанных сырых ссылок нужна, чтобы у вас не было дублей, когда вы туда новую необработанную ссылку будете добавлять. Ну и нужен признак обработанности. И я бы ещё добавил поле "следующее время обработки", если ссылки могут быть проблемными и скачиваться/обрабатываться не всегда с первого раза. Для таких ссылок это время переносится в будущее обработчиком этих ссылок.
Ну вот как-то так. То есть по сути получается две таблицы с единственной ответственностью:
- Обработка сырых ссылок
- Хранение готовых ссылок
Как именно хранить готовые ссылки разных типов, в одной таблице, или делить на несколько - опять же зависит от того, сколько этих типов, сколько записей в таблице и т.д. Т.е. опять же смотрим с точки зрения оптимизации работы с БД. Если там миллиарды записей каждого вида, которые сервис должен непрерывно лопатить, то лучше разделить на несколько таблиц. А если записей немного и сервис не критичный по времени на чтение/фильтрацию этих записей, то можно и в одну таблицу свалить.
Не уверен, что сильно помог, но рассуждать можно примерно так.