Pull to refresh
22
0
Алексей @pankraty

Разработчик

Send message

Спасибо, и правда интересная статья. Про абстракцию "бесконечный итератор timestamp-ов" я лично никогда не задумывался.

нужно было бы писать

var a = new NowService.GetNowTime();
var b = new AddDaysService().Calculate(a, 1);
b = new AddMinutesService().Calculate(a, 1);

Не-не-не! Никаких new NowService! Только DI, только хардкор!


public interface IJunkService
{
    DateTime DoJunkAction();
}

public class JunkService : IJunkService
{
    private readonly ITimeProviderService _timeProviderService;
    private readonly ITimeManipulationService _timeManipulationService;

    public JunkService(ITimeProviderService timeProviderService,
                       ITimeManipulationService timeManipulationService)
    {
      _timeProviderService = timeProviderService;
      _timeManipulationService = timeManipulationService;
    }

    public DateTime DoJunkAction()
    {
      var now = _timeProviderService.GetNowTime();
      var b = _timeManipulationService.AddDays(now, b);
      b = _timeManipulationService.AddMinutes(now, b);
      return b;
    }
}

Поначалу, возможно, выглядит абсурдно. Но, если подумать, так можно а) безболезненно обойти проблемы с рассинхронизацией времени на разных серверах / в разных часовых поясах (когда ХЗ что на самом деле вернет DateTime.Now) и б) легко и непринужденно протестировать логику, завязанную на события в будущем или прошлом. ITimeManipulationService, скорее всего, перебор, но если речь будет идти не про время, а про какие-то сущности, которые по-разному могут обрабатываться в разных странах/регионах/компаниях — такой подход оказывается довольно удобным (хотя, конечно, со своими издержками).

а это logical cohesion и он является плохой практикой. Модули группируются по функционалу а не по подобию.

С этим согласен, но я имел в виду не столько группировку в одном модуле, сколько выстраивание картины мира в голове разработчика. Если он знает, как в общем устроены сущности определенной категории в его проекте (те же репозитории, к примеру), то ему не нужно помнить каждую из них в лицо, чтобы представлять, для чего, что и как она делает. С «толстыми» сущностями такая унификация труднодостижима, у каждой своя индивидуальная специфика.
Разве это не очевидно?

Нет, не очевидно. Если классов будет 5 вместо 25, но функциональность будет той же, удержать их в голове будет ничуть не легче, т.к. единицей внимания все-таки является не класс сам по себе, а единица функциональности.
Кроме того, я не привязывался бы к конкретным цифрам 5-9, поскольку «удерживать внимание на N сущностей одновременно» это не то же самое, что «помнить и понимать устройство N сущностей» (второе, на мой взгляд, имеет куда большее значение в практической деятельности).
В случае большого количества мелких сущностей помнить и понимать их устройство, как ни удивильно, проще, т.к. они естественным образом группируются по подобию. Например, «это валидаторы, по одному на каждый тип сущности, они делают то-то и то-то», «а это репозитории, они устроены примерно так-то и так-то, вызываются обычно из таких-то мест», «вот эта пачка классов соответствует различным стратегиям, используются там-то, выбор стратегии зависит от того-то» и т.п. В случае больших классов с многочисленными методами и внутренними взаимосвязями когнитивная нагрузка выше, как результат, помнить и понимать их устройство — сложнее.
Есть теория управляемости, которая говорит, что у человека в голове помещается от 5 до 9 сущностей, так вот SRP этому явно противоречит.

Интересно, каким образом?
Это как раз легко.
1. Решение могло быть принято давно и не тобой, а ты теперь разгребаешь последствия нескольких лет его правильного и неправильного применения. При этом вторые обращают на себя куда больше внимания по понятным причинам, из-за чего может казаться, что они составляют 90% общего объема.
2. Решение могло быть принято тобой, но неверно понято рядом последователей. И поскольку некоторые подходы позволяют отстрелить себе ноги легче, чем другие, — есть основания «винить» (ну, точнее, признавать недостатки) фреймворки, которые в большей мере допускают неверное их использование.
Вы, конечно, можете строить базу исходя из того, что у клиента может быть несколько имен, отчеств и фамилий. Но вряд ли это хорошая идея. :-)

Да нет, иногда это просто-таки необходимо. На Госуслугах, например, я больше чем уверен, у физ. лиц хранится не по одному имени/фамилии. Да и в налоговой. Да и в банках… Да много где. Не самый удачный пример, короче )
Похоже, вы тоже используете подход с анемичной моделью, особо не задумываясь об этом. Удивлены, что это, оказывается, «антипаттерн»?
Соглашусь. Я бы еще дополнил таким соображением: если «приложение» — не самодостаточная система, а некая библиотека, решающая прикладную задачу с более менее четко очерченными границами (например, работа с XLS-файлами), то для нее использовать богатую модель с продуманной разветвленной иерархией классов является вполне оправданным. Благодаря тому, что границы намечены заранее, вполне реально запроектировать систему достаточно гибкой, чтобы адаптироваться под новые требования, при этом возникновение таких требований, которые поломают всю структуру, довольно маловероятно.
На противоположном полюсе я бы поставил энтерпрайз системы, особенно «полукоробочного» плана, когда компании продается готовый продукт, подвергаемый серьезной модификации под нужды конкретного заказчика. Заранее предусмотреть все требования даже одного заказчика — архисложная задача. А уж сделать так, чтобы будущие требования будущих клиентов без проблем укладывались в существующий продукт (который бы при этом не был «голым» фреймворком) — еще сложнее. Рано или поздно обязательно окажется, что допущения, справедливые для 10 клиентов, не соответствуют бизнес-модели 11-го. Для таких продуктов, как мне кажется, анемичная модель подходит весьма хорошо. В коробочном продукте реализуется базовая логика, отвечающая потребностям большинства заказчиков, а там, где логику надо переопределить, сделать это легко — достаточно подменить соответствующую службу, никак не нарушая работы остального кода.

Для других приложений может быть найдено место на этой оси где-то между двумя полюсами. Они оба имеют право на существование. Но когда один называют «паттерном» (_«Так делать правильно!»_), а второй — «анти-паттерном» (_«Дети, не делайте так!»_), то, ИМХО, второй подход незаслуженно маргинализируется.

Автор оригинальной статьи, пожалуй, несколько перувеличил (или чрезмерно выпятил) недостатки богатой модели, но основной его вывод — что анемичная модель является вполне жизнеспособным вариантом, который тоже стоит рассматривать, выбирая архитектуру приложения — я считаю справедливым.
Да, пожалуй, стремясь избавиться от англицизмов я несколько перегнул палку.

"Если мы сделали унифицированную модель самолет с определенным размахом крыльев и 2 реактивными двигателями, мы можем быть уверены, что любой из наших самолетов (военных, гражданских или грузовых) сможет сесть на ВВП полосу предназначенную для данного типа самолета. Это полиморфизм"


Либо я не до конца понял вашу аналогию, либо она неверна. В ней скорее говорится, что экземпляры классов самолётов, реализующих определенный интерфейс, могут быть приняты в качестве входных параметров экземплярами класса "аэродром". Полиморфное поведение не описано.


Полиморфизмом будет, например, реализация рулей высоты. В типовом (абстрактном) проекте определен штурвал, который можно перемещать к себе/от себя, изменяя "наклон" самолёта (угол атаки?) Как конкретно происходит его изменение — в типовом проекте не описано, а описано в проектах разных моделей самолетов: В гражданском используются рули высоты, а в истребителе — изменяемый вектор тяги двигателя. Это полиморфизм.

Достойное пополнение коллекции

    /*
        COME TO THE DARK SIDE!!!

                 _.-'~~~~~~`-._                                                    
                /      ||      \                                                   
               /       ||       \        
              |        ||        |                      
              | _______||_______ |                                                 
              |/ ----- \/ ----- \|                                                 
             /  (     )  (     )  \                                                
            / \  ----- () -----  / \                                               
           /   \      /||\      /   \                                              
          /     \    /||||\    /     \  
         /       \  /||||||\  /       \                                            
        /_        \o========o/        _\                                           
          `--...__|`-._  _.-'|__...--'                                             
                  |    `'    |                         

    */


Из заголовочной части одного очень заморочного модуля.
Разве что там авторизация какая-то — одним можно, другим нельзя.

Ну, во-первых, для этого. Никто не будет рад, если фотки из личного альбома вконтактике будут доступны кому угодно по прямому URL (хотя бы потому, что URL-ы сохраняются в истории браузера).

Навскидку еще пара вариантов.
* Отдавать картинку, которую пользователь редактирует онлайн — добавляет надписи, рамочки, эффекты и т.п.
* Картографический сервер, который рендерит участок карты в соответствии с параметрами в GET (координаты центра, масштаб, разрешение...)

Кроме принципа подстановки Лисков есть еще принцип открытости/закрытости. Предлагавшийся выше вариант с public interface ICartState куда лучше ему соответствует, ИМХО. В предлагаемом Вами варианте добавление новых состояний при изменении требований будет вызывать боль из-за разрастающихся switch-ей и необходимости изменять множество мест сразу — хотя именно этого хотелось бы избежать.


Навскидку: от бизнеса может придти требование — "а давайте, пользователь может в уже оплаченной корзине добавлять или убирать бесплатные опции — доставку, например, или подарок...". И вся стройная система состояний ломается, т.к. в PaidCartState внезапно надо добавить методы Add(Product product) и Remove(Product product) с дополнительными валидациями, а точно ли можно этот product в данном состоянии Add или Remove. Так что SRP размывается тоже.

Да, но покрыв их один раз модульными тестами, вы сможете не переживать за их корректность во всех других местах, где они будут использоваться.
Поддерживаю. Мне доводилось выполнять тестовое задание для одной конторы, в котором требовался очень простой (и явно не для использования в продакшене) функционал, но обставленный рядом дополнительных требований к используемым техникам и технологиям: реляционная СУБД, WCF-сервисы, UI на основе WPF, IoC и т.п. Такое задание, очевидно, служит именно для того, чтобы оценить степень владения кандидата стеком технологий, используемых на проекте, скорость работы, качество архитектуры, кода, документации. Уровень владения английским, в конце концов. Такой вариант оценки кандидата вполне оправдан, на мой взгляд.
И, кстати, когда я отправлялся на собеседование в другую контору, меня спросили, готов ли я выполнить тестовое задание, на что я им предложил посмотреть результаты задания, выполненного для другой компании, — всех это вполне удовлетворило, тратить время на еще одно задание не пришлось.

То, что описано у автора, реально больше похоже на развод.
Я не про то, что вы что-то сделали не так, у вас, я так понял, коммерческая версия, купленная для работы. Просто слова «справился за сутки, пробной версии для этого хватит» могут быть восприняты кем-то как руководство к действию — скачать пробную версию и запилить на ней промо-ролик, а это нарушение лицензионного соглашения. Просто хотел обратить на это внимание, чтобы новички по незнанию не вляпались.

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

Мне больше знакома другая ситуация — 200+ компонентов в проекте, 1 баг, который надо отловить (или небольшое изменение). В этом случае, хочешь не хочешь, надо разобраться в чужом коде, понять, что откуда берется, куда передается дальше, на что влияет и почему (в случае бага) работает не так. А потом вписать свое решение таким образом, чтобы ничего не сломать. Можно, конечно, попробовать переписать с 0, но это совершенно другая задача, с совершенно другими сроками.

Собственно, вот.
Есть еще Design Guidelines for Class Library Developers, которые зачастую берутся за основу для coding conventions на крупных проектах.

Information

Rating
4,621-st
Location
Саратов, Саратовская обл., Россия
Date of birth
Registered
Activity