Преимущество переноса условия из метода в фабрику
От: varenikAA  
Дата: 10.04.21 05:33
Оценка:
if-else-switch
Удивительный дядя Боб. Предлагает переместить код if в фабрику.
А в конце острегает использовать в методе make перечисление, т.к. это создаст зависимость.
Но это тем более странно, что и оригинальный код ничего сложного не делает, кроме как задает текстовую переменную.
Т.е. чтобы создать строку нужна фабрика, но при этом никакой типизации лишь чтобы избежать зависимости.
Мне кажется или это «одержимость» примитивами? Так ведь удобнее вообще все на указателях на сях закодить.
Полгода назад читал обратное Types as Sets (мне понравилось), что тип должен содержать только множество валидных значений.
Я озадачен, т.к. Боба уважаю за книгу чистая архитектура.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 10.04.2021 5:35 Разраб . Предыдущая версия .
Re: Преимущество переноса условия из метода в фабрику
От: LaptevVV Россия  
Дата: 10.04.21 07:28
Оценка: 5 (1)
Ну, взгляды меняются.
Но относительно типов мне все же ближе классическая точка зрения Хоара: типы — не множества.
И он тоже меняет свою точку зрения: он признал, что включение null в множество значений — это его ошибка на миллиард долларов.
Нам сами целые числа нафиг не нужны.
Нам нужны возможности оперирования ими.
Если мы определяем конечное множество, то необходимо определить операции на концах.
В Аде были попытки прямо в языке объявлять подмножества типов, но не совсем удачные.
Так как не было средств определить для подмножества операции на границах.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Преимущество переноса условия из метода в фабрику
От: fmiracle  
Дата: 10.04.21 07:49
Оценка: 5 (1) +1
Здравствуйте, varenikAA, Вы писали:

AA>if-else-switch

AA>Удивительный дядя Боб. Предлагает переместить код if в фабрику.
AA>А в конце острегает использовать в методе make перечисление, т.к. это создаст зависимость.
AA>Но это тем более странно, что и оригинальный код ничего сложного не делает, кроме как задает текстовую переменную.


Если только строку вычислить, то он и предлагает оставить перечисление.

Firstly, if the sole intent of the programmer is to translate:
0->'male',
1->'female'
otherwise -> 'unknown'

…then his refactoring #2 would be my preference.


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

However, I have a hard time believing that the business rules of the system are not using that gender code for making policy decisions. My fear is that the if/else/switch chain that the author was asking about is replicated in many more places within the code. Some of those if/else/switch statements might switch on the integer, and others might switch on the string. It’s not inconceivable that you’d find a if/else/switch that used an integer in one case and a string in the next!

The proliferation of if/else/switch statements is a common problem in software systems. The fact that they are replicated in many places is problematic because when such statements are inevitably changed, it is easy to miss some. This leads to fragile systems.



AA>А в конце острегает использовать в методе make перечисление, т.к. это создаст зависимость.


Это деление на компоненты и соблюдение границ. Ради одного перечисления добавлять кучу лишних зависимостей к своему модулю действительно может быть не очень-то удобно. Как в плане изолированной разработки, так и в плане того, что если у тебя пакеты начинают зависеть друг от друга, то далее между ними начинают появляться и другие зависимости, и такие поползновения надо постоянно пресекать.
Re: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 11.04.21 11:24
Оценка: 15 (1)
Здравствуйте, varenikAA, Вы писали:

AA>if-else-switch

AA>Удивительный дядя Боб. Предлагает переместить код if в фабрику.
AA>А в конце острегает использовать в методе make перечисление, т.к. это создаст зависимость.
AA>Но это тем более странно, что и оригинальный код ничего сложного не делает, кроме как задает текстовую переменную.

Вот что Боб сам пишет там:


"Firstly, if the sole intent of the programmer is to translate:

0->'male',

1->'female'
otherwise -> 'unknown'
…then his refactoring #2 would be my preference."

Т.е. если рассматривать только оригинальный код и нет других требований, он предпочитает #2

"However, I have a hard time believing that the business rules of the system are not using that gender code for making policy decisions. "


AA>Т.е. чтобы создать строку нужна фабрика, но при этом никакой типизации лишь чтобы избежать зависимости.


Немного не так. Создать не строку а экземпляр базового класса, что-то типа


abstract class Gender 
{
    abstract string ToString();
}

class Male : Gender 
{
    override string ToString() => "male";
}

class GenderFactory 
{
   Gender CreateGenderByName(string genderName) 
     => genderName switch {
         "male" => new Male();
         "female" => new Female();
         "unknown" => new UnknownGender()
     };
}


Там не написано про "никакой типизации" там написано, про то, что не надо строчку заменять энамом.

Представьте, например, что эта строчка хранится где-то в конфиге или в БД. Если мы заведем энам, то мы должны будем внешним модулям как-то указывать как работать с конкретными значениями энама, как делать элементы энама из строчек и так далее. А так, внешний код может даже не знать о том, сколько у нас есть полов (ну или гендеров) и мы можем завести их хоть больше десятка. К ак фейсбук

Если внешнему коду надо будет узнать, например, с представителями какого пола предпочитает заниматься сексом представитель данного пола, или какую одежду уме лучше рекомандовать, мы заводим абстрактные методы в gender и реализуем их в конкретных полах при этом остальной код не надо оповещять об изменении списка полов. Можно даже не давать ему доступ к конкретным полам (сделать их internal) и мы точно будем уверены, что нам не надо менять ничего кроме кода модуля Gender при изменении количества полов.
Re: Преимущество переноса условия из метода в фабрику
От: vsb Казахстан  
Дата: 11.04.21 11:36
Оценка: +1
Я считаю, что он не прав. Нет ничего плохого в switch-ах по всей программе. Просто потому, что код со switch-ом будет именно в том месте, где он должен быть. А вот если собрать разнородный код со всей системы в один класс, вот это будет полная мусорка. И всё для того, чтобы не писать switch. В общем это очень напоминает старые дебаты по поводу "правильного ОО" против анемичной модели (я тут на стороне последнего варианта). Причём история показывает, что "правильное ОО" как-то со временем уже уходит, во некоторых новых языках его уже и нет в полноценном варианте.

Но, конечно, в языке должны быть enum-ы и должен быть switch, который будет ругаться при компиляции, если не все варианты перечислил. Т.е. если добавляешь новое значение, то не забудешь добавить новое поведение. Если сравнивать именно этот пример со строками, то тут может и есть смысл сделать с объектами, но это только от бедности языка.
Отредактировано 11.04.2021 11:36 vsb . Предыдущая версия .
Re[2]: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 11.04.21 13:18
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Я считаю, что он не прав. Нет ничего плохого в switch-ах по всей программе.




отсюда

Есть нечто плохое. Представьте, что нужно сделать систему с плагинами, причем добавление пола должно осуществляться плагином.

Как вы это сделаете со свитчами по все программе?

И у ОО подхода и у ФП подхода есть свои плюсы.
Re[3]: Преимущество переноса условия из метода в фабрику
От: vsb Казахстан  
Дата: 11.04.21 13:53
Оценка: 1 (1)
Здравствуйте, no4, Вы писали:

vsb>>Я считаю, что он не прав. Нет ничего плохого в switch-ах по всей программе.


no4>Image: OOP_FP_extend_easy_hard.jpeg


Непонятно, почему в FP сложно добавить вариант. Добавляем вариант, компилируем программу, вылазит кучу ошибок. Каждая ошибка это то место, где нужно добавить код обработки. Собственно всё.

no4>отсюда


no4>Есть нечто плохое. Представьте, что нужно сделать систему с плагинами, причем добавление пола должно осуществляться плагином.


no4>Как вы это сделаете со свитчами по все программе?


Всё же это уже другая задача. В такой задаче ОО-подход нужен, соглашусь. Но тут речь идёт не о трудоёмкости, а принципиальной возможности.

Хотя я бы и этот подход сделал бы по-другому. По-мне лучше вынести такие операции в интерфейс плагина и всё. Что-то вроде

interface State { ... }

interface Plugin {
    State init();
    State processValidInput(byte[] input, State state);
    State processInvalidInput(byte[] input, Exception error, State state);
    void finish(State state);
}


В таком варианте можно и state добавлять (например с нужными полями), и обработка остаётся в классе с поведением.
Re[2]: Преимущество переноса условия из метода в фабрику
От: varenikAA  
Дата: 12.04.21 01:53
Оценка:
Здравствуйте, no4, Вы писали:

no4>
no4>class GenderFactory 
no4>{
no4>   Gender CreateGenderByName(string genderName) 
no4>     => genderName switch {
no4>         "male" => new Male();
no4>         "female" => new Female();
no4>         "unknown" => new UnknownGender()
no4>     };
no4>}
no4>


Только тогда уже логичней интом параметризировать функцию и последний кейс у вас, возможно опечатка, по "unknown", а ведь туда может любая строка зайти
наверно имелось ввиду _ => new UnknownGender(genderName)

Но я бы все же сделал так (два варианта) (код на F#)

module GenderTypes =
    type Gender =
        | Male
        | Female

module GenderUtils =
    open GenderTypes

    let genderResult x =
        match x with
        | 1 -> Ok Male
        | 2 -> Ok Female
        | _ ->
            sprintf "'%d' - неопеределенное значение пола" x
            |> Error

    let genderChoice x =
        match x with
        | 1 -> Some Male
        | 2 -> Some Female
        | _ -> None

    let unwrapGender (g: Gender option) =
        match g with
        | Some x -> x
        | None -> failwith "пол неопределён"

open GenderTypes
open GenderUtils

let m = genderChoice 10
let g = unwrapGender m


О границах компонентов в F# заботиться не нужно т.к. компилятор обязан знать о всех используемых типах(по-моему он однопроходный, т.е. для него важен порядок компиляции исходных файлов).
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Преимущество переноса условия из метода в фабрику
От: varenikAA  
Дата: 12.04.21 02:11
Оценка:
Здравствуйте, no4, Вы писали:

no4>отсюда


Эта проблема решается при помощи как раз системы типов и CLOS
Т.е. в систему должны попадать уже распарсинные значения, а не голые инты/строки.
Тогда обобщенный метод легко добавляет новое поведение.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[4]: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 12.04.21 06:07
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Здравствуйте, no4, Вы писали:



vsb>Непонятно, почему в FP сложно добавить вариант. Добавляем вариант, компилируем программу, вылазит кучу ошибок. Каждая ошибка это то место, где нужно добавить код обработки. Собственно всё.


В ОО не выставляется наружу внутренности того, что такое вариант.
В ОО можно доабавить свой вариант за пределами модуля, главное, чтобы он реализовывал контракт абстрактного варианта.
Т.е. есть явное описание интерфейса того, что предусмотрено для добавления нового варианта чтобы он вписался в систему.


vsb>Всё же это уже другая задача. В такой задаче ОО-подход нужен, соглашусь. Но тут речь идёт не о трудоёмкости, а принципиальной возможности.


Это примерно та же самая задача. Просто когда расширение владеется другими людьми хорошо иллюстрирует трудоемкость добавления варианта.
Но абстрагирование и разделения по модулям так же работает, когда код владеется другой командой в том же проекте или просто вообще у нас много кода.


vsb>Хотя я бы и этот подход сделал бы по-другому. По-мне лучше вынести такие операции в интерфейс плагина и всё. Что-то вроде



vsb> State processValidInput(byte[] input, State state);

vsb>В таком варианте можно и state добавлять (например с нужными полями), и обработка остаётся в классе с поведением.

Я не очень понял. Вы можете привести чуть больше кода используя пример с полами?
Re[4]: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 12.04.21 09:48
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Здравствуйте, no4, Вы писали:


AA>Т.е. в систему должны попадать уже распарсинные значения, а не голые инты/строки.


Это как? Вот лежит на диске файлик, там написано 1 для пола. Так как формат такой. Как из него сделать Gender если ни на каком этапе в систему типов не попадает int
Re[3]: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 12.04.21 09:52
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Здравствуйте, no4, Вы писали:


AA>Но я бы все же сделал так (два варианта) (код на F#)


...

AA>О границах компонентов в F# заботиться не нужно т.к. компилятор обязан знать о всех используемых типах(по-моему он однопроходный, т.е. для него важен порядок компиляции исходных файлов).


Там же есть модули, значит все то же самое. Получается мы такой модуль новыми гендерами расширить не можем. Только менять.
Re[5]: Преимущество переноса условия из метода в фабрику
От: varenikAA  
Дата: 12.04.21 12:16
Оценка:
Здравствуйте, no4, Вы писали:

AA>>Т.е. в систему должны попадать уже распарсинные значения, а не голые инты/строки.


no4>Это как? Вот лежит на диске файлик, там написано 1 для пола. Так как формат такой. Как из него сделать Gender если ни на каком этапе в систему типов не попадает int

систему типов описывающих бизнес-логику. на границе инфраструктурный код, который склеивает 1 и доменный тип Gender. внутри системы нам незачем опериравать примитивными типами.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[6]: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 12.04.21 12:42
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Здравствуйте, no4, Вы писали:


AA>>>Т.е. в систему должны попадать уже распарсинные значения, а не голые инты/строки.


no4>>Это как? Вот лежит на диске файлик, там написано 1 для пола. Так как формат такой. Как из него сделать Gender если ни на каком этапе в систему типов не попадает int

AA>систему типов описывающих бизнес-логику. на границе инфраструктурный код, который склеивает 1 и доменный тип Gender. внутри системы нам незачем опериравать примитивными типами.

Тогда в чем разница с фабрикой? Фабрика стоит на границе и деллает из int Gender.
Re[7]: Преимущество переноса условия из метода в фабрику
От: varenikAA  
Дата: 12.04.21 12:51
Оценка:
Здравствуйте, no4, Вы писали:

no4>Тогда в чем разница с фабрикой? Фабрика стоит на границе и деллает из int Gender.

Небольшая, но существенная, фшарп возвращает Ok gender или Error message.
В коде за сишарпе в случае ошибки возвращается наследник базового, т.е. нельзя опеределить правильно ли отработала фабрика.
UnnkownGender валидный наследник абстрактного Gender, может ли мы его считать ошибкой?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[8]: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 12.04.21 13:18
Оценка: +1
Здравствуйте, varenikAA, Вы писали:

AA>Здравствуйте, no4, Вы писали:


no4>>Тогда в чем разница с фабрикой? Фабрика стоит на границе и деллает из int Gender.

AA>Небольшая, но существенная, фшарп возвращает Ok gender или Error message.

Ну это в принципе можно сделать и на C# (с некоторыми ограничениями пока нет чего-то типа такого)

AA>В коде за сишарпе в случае ошибки возвращается наследник базового, т.е. нельзя опеределить правильно ли отработала фабрика.

AA>UnnkownGender валидный наследник абстрактного Gender, может ли мы его считать ошибкой?

Если он наследник, то должен быть валидным иначе не наследник.

Можно вместо этого выбрасывать исключение, например.

Разница discriminated union vs иерархия сабтайпинга скорее в расширяемости вариантов, особенно сторонними расширителями. Об чем и статья, на которую я ссылался.
Re[4]: Преимущество переноса условия из метода в фабрику
От: varenikAA  
Дата: 14.04.21 14:58
Оценка:
Здравствуйте, no4, Вы писали:

no4>Там же есть модули, значит все то же самое. Получается мы такой модуль новыми гендерами расширить не можем. Только менять.


Да, точно, парадокс в том, что лиспах все это и даже больше и проще уже давно есть.

(defgeneric q (a))

(defmethod q ((a string))                  
     (print a))

(defmethod q ((a integer))                  
     (print a))

(defmethod q ((a (eql 0)))                  
     (print "Method called with eql a 0"))

(defmethod q ((a (<; 0)))                   
     (print "Method called with < 0 a"))
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[2]: Преимущество переноса условия из метода в фабрику
От: · Великобритания  
Дата: 14.04.21 16:32
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Я считаю, что он не прав. Нет ничего плохого в switch-ах по всей программе. Просто потому, что код со switch-ом будет именно в том месте, где он должен быть. А вот если собрать разнородный код со всей системы в один класс, вот это будет полная мусорка. И всё для того, чтобы не писать switch.

Тут ведь как: а вот если собрать весь однородный код со всей системы в один клас, вот это будет красота и счастье.
Ведь иногда так и получается, что все эти размазанные по всему коду switch-и на самом деле описывают одну и ту же логическую сущность, часто напрямую соответствующую бизнес-требованиям.
И даже если понадобится какое-то расширение, чтобы не получалась мусорка, то ОО предлагает другие подходы, visitor тот же.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: Преимущество переноса условия из метода в фабрику
От: no4  
Дата: 16.04.21 06:56
Оценка:
Здравствуйте, varenikAA, Вы писали:

AA>Здравствуйте, no4, Вы писали:


no4>>Там же есть модули, значит все то же самое. Получается мы такой модуль новыми гендерами расширить не можем. Только менять.


AA>Да, точно, парадокс в том, что лиспах все это и даже больше и проще уже давно есть.


У меня поверхностное представление о Лиспе.

Как там со статическими проверками и сокрытием реализациии?

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

Например условно у нас есть три модуля:

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

2. Facebook extension
(расширение набора гендеров до 54)

3. Социально вещевая сеть — использует операции из 1. для реализации бизнес логики знакомства и подбора одежды.


Хочется чтобы:
1. Авторы Facebook extension знали минимальный набор операций которые им надо реализовать для гендера, чтобы он подходил для всех пользователей
2. Авторы социальной сети знали, на какой минимальный набор операций им можно надеяться, чтобы использовать все расширения
3. Авторы модуля Гендер знали что является публичным интерфейсом и что они не могут менять чтобы не нарушать обратную совместимость
4. Они знали что они могут менять не нарушая совместимости

Преставим что это все сложные модули и мы хотим контроллировать это при помощи автоматической проверки.

Как нам этого достичь в Lisp?
Re[6]: Преимущество переноса условия из метода в фабрику
От: varenikAA  
Дата: 16.04.21 07:26
Оценка:
Здравствуйте, no4, Вы писали:


no4>У меня поверхностное представление о Лиспе.


no4>Как там со статическими проверками и сокрытием реализациии?


no4>Например можно декларировать абстрактный пол и набор операций, который каждый уважающий себя пол должен реалзовывать?


Мне кажется сложно найти что-то чего нет в лиспах(я сам только основы изучил)
https://quickref.common-lisp.net/abstract-classes.html#The-abstract_002dclasses-system
Но вот с другой стороны если чего-то нет, то быть может это не очень удачная идея.
Так я видел реализацию маттерн матча для лиспа, но зачем если мультиметоды легко решают эту задачу, пусть и не контролирует все кейсы.
но на то он и динамический чтобы дать большую свободу. лиспы лучше подходят где важна не абсолютная корректность и максимальная производительность,
а нечто другое. холивар. )))
☭ ✊ В мире нет ничего, кроме движущейся материи.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.