Re[23]: Почему объектно-ориентированное программирование про
От: vdimas Россия  
Дата: 23.02.11 23:56
Оценка:
Здравствуйте, gandjustas, Вы писали:


G>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.


Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу. Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?
Re[10]: Почему объектно-ориентированное программирование про
От: vdimas Россия  
Дата: 24.02.11 06:02
Оценка: +1
Здравствуйте, samius, Вы писали:


S>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.


У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие.

S>Т.е. как бы можно взять за основу ФП декомпозицию, подменить кортежи бездушными структурами, АДТ подменить на гомоморфные иерархии, где в базе будет абстрактный интерфейс, составленный из набора функций, работающих с этим АДТ. Иммутабельность сохраняется.


Бенефит потоковой безопасности достигается так же локальностью ссылок. Тем не менее, иммутабельность на этапе обработки данных дает очень важное кач-во при последующей смене состояния. Ниже пройдусь.

S>В итоге получается как бы и ООП, но с ФП дизайном.


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

S>В том что это возможно, я нисколько не сомневаюсь, т.к. сам тяготею к такому стилю. Интересно обсудить его в плане обилия рефакторинга.


ФП подход сидит на алгоритмической декомпозиции. А та принципиально меньше тяготеет к рефакторингу, т.к. зависимостей в рамках одной ф-ии всяко меньше, чем сразу у группы оных.

Как уже тут было упомянуто, тяга к инкапсуляции подробностей реализации в больших ООП-проектах оборачивается тем, что приличная часть функционала делается многократно, но "чуть чуть" уникально для каждого объекта. И рефакторинг, помимо прочего, постоянно борется и с этим, по мере выявления схожей функциональности в соседних иерархиях. Т.е, хотя ООП и было призвано обеспечивать большее повторное применение кода, я пока вижу несколько обратное. А если бы сия функциональность была сразу доступна на уровне, скажем, модуля? Но это тоже не просто, ведь мы работаем с внутренним состоянием объектов. А что, если это состояние составлять из неких "стандартных кубиков" под нашу задачу? Мы ведь в процессе тщательного рефакторинга и объектной декомпозиции и так к этому приходим, правильно? За много итераций. Но в случае процедурного подхода, и аналогично ФП-подхода, мы вынуждены эти "стандартные кубики" разрабатывать сразу, как результат попытки реализации функциональных требований к программе. По-сути, мы вынуждены будем разработать представление/абстракции ДАННЫХ, и завязать их на алгоритмы по их трансформации. В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает. Применяя технику ООП, сии кубики можно сделать во-первых безопасными (располагаем инструментом инкапсуляции), во-вторых, нарисовать им удобный АПИ. Ну и согласен, гомоморфные наборы этих кубиков, если делать на ООП — вообще убийственная сила в плане прозрачности дизайна.

А что собственно произошло? Мы позволили процедурам и функторам принимать как аргументы и возвращать как результат объекты. Отличное дополнение к алгоритмической декомпозиции. Далее. Пытаемся реализовать ту самую функциональность, которая идет как функциональные требования. (Без всяких глобальных переменных, по крайней мере без мутабельных). В каких-то местах мы видим, что упираемся. Это происходит при надобности в какой-то точке вычислений обеспечить персистентность данных м/у вызовами. Т.е. сохранить состояние. Вот! Усек что произошло? Вместо заведомого "от балды" рисования семейства объектов-акторов, как участников "первого варианта дизайна" (который будет потом многократно перерефакторен), мы выходим на список объектов как бы автоматически, через мн-во состояний, требующих персистентности. И уже с готовыми "кубиками" наперевес, так что составить из них в нужном месте композицию получается совсем простым делом. Утрирую, понятно, но очень близко к происходящему.


S>Пробег. Информация безусловно полезная, но применительно к дизайну, она просто добавит карандашей, которые нужно сгрызть.


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


V>>А не обязательно чистое ФП, со всеми модными фокусами. ФП сидит на функциональной декомпозиции, а это практически первое, чему учатся при обучении программированию.

S>Дык и проблема в том что чистое ФП технически сложно на языках имеющих парадигму менее чем гибридную по отношению к ФП. Так или иначе получается адская мешанина.

Ты поменьше функциональщиков слушай.
Я тут многократно предлагал взглянуть на объекты как на автоматы (а они и есть автоматы), и позаимствовать оттуда кой-чего. Чем преобразователь-автомат отличается от простой цифровой функции? Наличием памяти. Cтруктура автомата (Мура) такова:
1. функция выходов, которая вычисляется от ф-ии входов и текущего состояния.
2. функция вычисления следующего состояния от входов и текущего состояния.
3. собственно память для хранения состояния.

п.п.1-2 абсолютно "чисты" с т.з. ФП, что как бэ намекает на уместность применения этого подхода для реализации объекта-автомата.

Вернемся к нашему подходу. Итого, "универсальные кубики", представляющие данные для сохранения в "памяти", уже есть. Ф-ия вычисления след. состояния, то бишь ф-ия обработки этих кубиков, тоже есть — мы с нее начали разработку. Теперь нам собрать "автомат", то бишь объект из этого — вовсе элементарно. И при этом новое состояние мы можем менять транзакционно (как работает регистр-защелка в цифровой электронике), тогда мы не будем иметь вообще никакой возможности вогнать автомат в невалидное состояние. Т.е. отделив в явном виде ф-ии вычисления след. состояния от собственно шага обновления состояния, мы можем добиться уникального в плане надежности качества — устойчивости к исключениям. Скажу по секрету, что сей устойчивостью 99% современного кода не обладают, потому как изменяют свое состояние обычно "постепенно", по мере работы. Т.е. объекты обычно ходят по промежуточным состояниям, и в случае исключения могут там и остаться. И что обычно происходит? Зачеркивается целиком всё, потому как разработка кода восстановления после ошибки больно трудоемка. В итоге, мы отказываемся еще от одной полезной практики, под названием "let it fail".

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

Почему же функциональщики так жужжат о вреде смешения парадигм? Тут стоит вспомнить, что в деле разработки ПО всегда была куча вопросов, которые хотелось вывести на кончике пера, но они были для общего случая недоказуемы. Из-за той самой проблемы останова и прочих. Однако, было показано, что при наличии неких ограничений, под многое становится возможным подвести точную теорию. В итоге, "чистое ФП" — это наиболее ограниченная техника на сегодня, но благодаря ограниченности — единственная, имеющая хоть какой-то мат.аппарат. Поэтому, при нарушении наложенных ограничений, весь этот матаппарат нарушается. Но это с т.з. ФП. Что касается ООП, то он наоборот, обогащаемся целым набором замечательный св-в. Бери цифровую электронику. Это почти ООП (КОП в чистом виде) — интерфейсы и их реализации. И никто не страдает, что на одной плате есть как "чистые" цифровые ф-ии, так и россыпь автоматов. Прекрасно оно совместно работает. За счет той самой транзакционности смены состояний автоматов. Справедливости ради, в тех местах, где смена состояний растягивается на несколько шагов, в цифровой технике начинаются те же проблемы, что в ООП. И рядом сажают watch-dog таймеры, которые делают сброс охраняемой схемы, если её переклинило/зациклило в невалидном состоянии.


S>Я бы сказал что знаком с китом, а не владею.


Не скромничай. Создание делегата по нестатическому методу — это всегда замыкание, еще со времен первого дотнета. А ты наверняка делегатов насоздавал за свою практику уже немало.


S>В шарпе — да. Куда сложнее на C++ без 0x, с которым приходится иметь дело.


Дык, а boost:bind? А старые добрые std::bind1st, std::bind2nd? Та же фигня. А слоты и сигналы QT?


S>Мне довольно удобно. неудобно как раз видеть решение в ФП виде и адаптировать его к ООП.


Наверно, от образа мыслей зависит. По мне ФП хорошо, пока мы производим вычисления, и плохо, когда нам результат этого вычисления надо куда-то девать. Монада IO в Хаскеле как раз помечает те места, где "чистое ФП" умывает руки.


S>ООП ведь не запрещает анализ!


Ни одна методология не запрещает. Мое ИМХО о том, что ООП поощряет начинать сразу с квадратиков.

S>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи.


Это в конкретном месте детали свежи. А если имеем несколько накопленных TODO, то можно попытаться обозреть проблему чуть более со стороны. И часто бывает так, что удовлетворяя один из них, можно удовлетворить целую пачку. В общем, перед решением любой задачи, желательно как можно больше вводных/требований. Хотя, каждый случай уникальный, понятно, и универсальных советов тут нет. Совет "рефакторить сразу" так же далек от универсальности.

S>TODO здесь поможет только в том случае, когда видно что плохо, но цель не ясна, т.к. связано с кодом, который в другом владении, либо неясна общая концепция.


Именно. Порой лучше оставить TODO с обозначением временного решения, до прояснения, с чего вообще такая ситуация возникла. При разделении труда в команде, с помощью этих TODO люди создают друг другу требования к внутреннему АПИ/функциональности, а современные IDE прекрасно составляют из них список в отдельном окошке.

S>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.


Ну естественно, функциональные требования в приоритете над требованиями дизайна. Но они обычно для удовлетворения требуют не столько рефакторинга, сколько доработки функциональности, что как бэ слегка иное.
Re[24]: Почему объектно-ориентированное программирование про
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.02.11 08:55
Оценка:
Здравствуйте, vdimas, Вы писали:

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



G>>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.


V>Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу.

Я тоже не видел. Более того, сама парадигма ООП этому противоречит.

V>Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?

typeclasses в хаскеле.
Re[17]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 10:46
Оценка:
Здравствуйте, vdimas, Вы писали:

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


I>>Покажи как твой декоратор можно протестировать в изолированом виде


V>Ну блин, техника изоляции при тестировании всегда одна — через заглушки. А способов исполнения сих заглушек множество:


Я скипнул порожний текст. Покажи, как ТВОЙ декоратор можно протестировать в изолированом виде.

Мне очень хочется посмотреть, как же ты зависимость от ThirdParty заменишь на заглушку.
Re[29]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 10:59
Оценка:
Здравствуйте, vdimas, Вы писали:

I>>А кто тебе сказал, что есть ссылка на логгер ? Ты слишком много на С++ сидишь. Зависимость может быть, а вот состояния может и не быть и это нормально.

I>>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.

V>Все ясно. Что есть по твоему "состояние"?


Элементарно — персистед данные.

I>>Это в С++, сочувствую.


V>При чем тут С++, если в дотнете есть статические методы и поля. Это и есть "глобальное состояние". Для дотнета, правда, ограниченное доменом, но для нашего обсуждения не принципиально. А характер получаемой инкапсуляции сравним с оной в модулях.


Принципиально. Состояния может и не быть, а зависимость будет в любом случае.

I>>Не ясно, как ты понимаешь эту декомпозицию. Из твоих примеров этого понимания вообще не следует.


V>Декомпозиция — это разбиение сложного решения на части. Сам термин в чистом виде относится к случаю, когда сохраняется исходная функциональность, хотя мы тут его используем порой вольно, угу. В случае развития функциональности, как в твоем примере, тут минимум 2 шага: сначала декомпозиция исходного решения, потом его доработка.


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

I>>Ога, сделать жосткую зависимость от другого класса


V>Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.


// тут наследуем, т.к. PreDo()/PostDo() требуют особого доступа к базе по условию,
class PreAndPostDecorator : ThirdPartyClass  // вот это жосткая зависимость 
{
  public void PreDo() {}
  public void PostDo() {}
}

// структурная композиция
class PreAndPostDoerDecorator : IDoer
{
  private PreAndPostDecorator _decorator = new PreAndPostDecorator(); // и это жосткая зависимость  
 
  PreAndPostDoerDecorator(IDoer doer){  _doer = doer;} 

  void Do() {
    _decorator.PreDo();
    _doer.Do();
    _decorator.PostDo();
  }
}





I>>Опаньки, щас ты снова заговорил про связанность


V>Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?


Ранее ты вещал про состояние

V>Нет, я хочу понять — почему именно так. Т.е. выйти на "локальное ТЗ".


Уже давно было дадено это "локальное ТЗ".

I>>Это тот же декоратор При том не самый удачный.


V>Не надо пытаться натягивать туда паттерны ООП, бо его там не осталось. В ФП чуть менее чем все паттерны пляшут от трех базовых комбинаторов и техники частичного применения.


Адаптер это паттерн более древний, чем ООП

I>>Например потому что есть зависимость от классов Context и DoerModule.


V>Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer.


Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.

V>>>Уффф... Ну вопрос тем более в силе, при чем тут тогда твое требование провести объектную декомпозицию?


I>>объект == функциональный элемент


V>С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.


Это в с++ тбе надо искать состояние.
Re[31]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 11:05
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Дабы не повторяться, предлагаю продолжить здесь: http://rsdn.ru/forum/philosophy/4170909.aspx
Автор: vdimas
Дата: 24.02.11

V>Там я пояснил суть проблемы восприятия этой фразы.

V>>>
V>>>Action<Doer> acceptDoer = (doer) => someObj.AcceptDoer(doer);
V>>>


I>>Да, круто. Это равносильно обычному вызову AcceptDoer


V>Это абстрагирование от конкретного AcceptDoer. Почувствуй разницу.


"мне надо изменить поведение некоторый реализаций не переписывая все разновидности и клиенты IDoer "

Нахрена тебе AcceptDoer менять и абстрагироваться ?

Еще раз

1 Есть некоторые реализации IDoer. Их модифицировать нельзя, например за отсутствием исходного кода.
2 Есть конкретная реализация IDoer. Её модифицировать можно.
3 Есть AcceptDoer который модифицировать нельзя, например за отсутствием исходного кода.

Задача — модифицировать поведение AcceptDoer для ВСЕХ IDoer.

Чем тебе поможет абстрагирование от AcceptDoer в этой задаче ?
Re[24]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 11:07
Оценка:
Здравствуйте, vdimas, Вы писали:

G>>Разговор был о проектировании, а ты как-то внезапно съехал на внутренности компилятора, подменяя суть терминов.


V>Просто я еще не видел компиляторов ООП-языков, чтобы при наследовании реализации наследник не агрегировал базу. Скажу больше, я даже не представляю, как это обойти. У тебя есть предложения?


Вот это агрегирование базы ты похоже и называешь "разделение состояния"
Re[10]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 11:13
Оценка:
Здравствуйте, samius, Вы писали:

S>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.


Традиционному ООП это никак поперек горла быть не может


V>>Всё-равно автоматически по достижении некоторого порога. Однажды становится трудно просто прочесть код, даже если он хорош. И единственно правильное решение — декомпозировать, передокументировать и прочесть заново. Это может сэкономить часы и это дополнительный review кода. Оно как эффект катастрофы в природе, во вменяемой команде выполняется на автомате всеми участниками.

S>(выделил чуть выше)
S>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи. TODO здесь поможет только в том случае, когда видно что плохо, но цель не ясна, т.к. связано с кодом, который в другом владении, либо неясна общая концепция.
S>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.

Любой код имеет свой цикл жизни. Рефакторинг удлинняет этот цикл жизни. Но сделать бесконечным просто не получится. Ну и издержки по вермени/деньгами никто не отменял. В конечном итоге становится проще выбросить хотя бы некоторые части и написать их заново.
Re[11]: Почему объектно-ориентированное программирование про
От: samius Япония http://sams-tricks.blogspot.com
Дата: 24.02.11 11:40
Оценка:
Здравствуйте, vdimas, Вы писали:

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


S>>...Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.


V>У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие.

Не совсем так. поведение функции может зависеть от состояния извне, переданного аргументом. Ключевое отличие — внутри или снаружи. Но и это отличие тает при упоминании о том что состояние передается неявно через this. Остается совсем незначительная деталь, отделяющая чистую функцию от метода объекта — функция не может менять внутреннюю память аргумента. (Уверен, ты все это знаешь. Я просто описываю ракурс, под которым я вижу немалую схожесть функции и объекта.) В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.

V>Бенефит потоковой безопасности достигается так же локальностью ссылок. Тем не менее, иммутабельность на этапе обработки данных дает очень важное кач-во при последующей смене состояния. Ниже пройдусь.

потоковую безопасность я пока даже не рассматриваю.

V>ФП-подход — это подход, ориентированный на функции высших порядков, как я себе представляю, чем он отличается от обычного процедурного подхода. Конечно, тоже полезная штука для абстрагирования, но скорее как инструмент для избавления от лишних зависимостей и от россыпи маленьких интерфейсов, чем как цель дизайна.

Естественно ФП не цель, а средство.

S>>В том что это возможно, я нисколько не сомневаюсь, т.к. сам тяготею к такому стилю. Интересно обсудить его в плане обилия рефакторинга.


V>ФП подход сидит на алгоритмической декомпозиции. А та принципиально меньше тяготеет к рефакторингу, т.к. зависимостей в рамках одной ф-ии всяко меньше, чем сразу у группы оных.


V>Как уже тут было упомянуто, тяга к инкапсуляции подробностей реализации

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

V>А что, если это состояние составлять из неких "стандартных кубиков" под нашу задачу? Мы ведь в процессе тщательного рефакторинга и объектной декомпозиции и так к этому приходим, правильно? За много итераций.

да, но я все время пытаюсь перевести разговор в следующее русло: что бы было, если бы ООП кубики строили с ФП конца.

V>Но в случае процедурного подхода, и аналогично ФП-подхода, мы вынуждены эти "стандартные кубики" разрабатывать сразу, как результат попытки реализации функциональных требований к программе. По-сути, мы вынуждены будем разработать представление/абстракции ДАННЫХ, и завязать их на алгоритмы по их трансформации.

да. А теперь возьмем и нарисуем ООП кубики по ФП наброску.

V>В ФП-языках эти кубики выглядят как алгебраические типы или туплы, иногда именованные — структуры/кортежи. Все кишки наружу и АПИ к ним не нарисуешь, поэтому "чистое ФП" меня не торкает.

Слишком быстрый переход. Почему АПИ не нарисуешь? Рисовать можно все что угодно, кроме способов изменения внутренних состояний.

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

они абсолютно безопасные. инкапсуляция ФП не противоречит. И АПИ на иммутабельных объектах тоже может быть удобным, разве что менее привычным.

V>Ну и согласен, гомоморфные наборы этих кубиков, если делать на ООП — вообще убийственная сила в плане прозрачности дизайна.

Согласен. Но ничто не мешает ОО кубикам, построенным из ФП декомпозиции лежать в гомоморфной иерархии.

V>А что собственно произошло? Мы позволили процедурам и функторам принимать как аргументы и возвращать как результат объекты. Отличное дополнение к алгоритмической декомпозиции. Далее. Пытаемся реализовать ту самую функциональность, которая идет как функциональные требования. (Без всяких глобальных переменных, по крайней мере без мутабельных). В каких-то местах мы видим, что упираемся. Это происходит при надобности в какой-то точке вычислений обеспечить персистентность данных м/у вызовами. Т.е. сохранить состояние. Вот! Усек что произошло? Вместо заведомого "от балды" рисования семейства объектов-акторов, как участников "первого варианта дизайна" (который будет потом многократно перерефакторен), мы выходим на список объектов как бы автоматически, через мн-во состояний, требующих персистентности. И уже с готовыми "кубиками" наперевес, так что составить из них в нужном месте композицию получается совсем простым делом. Утрирую, понятно, но очень близко к происходящему.

Т.е. ты предлагаешь вставлять мутабельные объекты там где требуется персистентность состояний между вызовами. Остается вопрос где грань между требуется и не требуется. Ведь ФП предлагает средства по передаче состояний между вызовами без персистентности (рекурсия, монада state, зиппер). На самом деле вопрос о грани между требуется и не требуется ли персистентность — очень скользкий. Легко впасть в крайность, когда она требуется везде — получаем голый императив, не требуется нигде — чистое ФП, или местами — гибрид.


V>Вообще-то фокус был на порядок работ, чтобы минимизировать кол-во съеденных карандашей. По мне рефакторинг и есть перманентная грызня карандаша, только уже с помощью мышки и клавы.

Да, так и есть. Вместо витания в облаках, точится код во плоти. И не только перманентная грызня, но и персистентная. А значит требует больше ресурсов.

S>>Дык и проблема в том что чистое ФП технически сложно на языках имеющих парадигму менее чем гибридную по отношению к ФП. Так или иначе получается адская мешанина.


V>Ты поменьше функциональщиков слушай.

Наоборот, хотел бы послушать.

V>Я тут многократно предлагал взглянуть на объекты как на автоматы (а они и есть автоматы), и позаимствовать оттуда кой-чего. Чем преобразователь-автомат отличается от простой цифровой функции? Наличием памяти. Cтруктура автомата (Мура) такова:

согласен, объекты есть автоматы.
V>п.п.1-2 абсолютно "чисты" с т.з. ФП, что как бэ намекает на уместность применения этого подхода для реализации объекта-автомата.
память автомата может быть не только внутри объекта. Её может предоставлять клиент автомата, потому автоматы могут быть абсолютно чистыми, впрочем вместе с клиентами (http://www.rsdn.ru/article/haskell/HaskellStateMachine.xml
Автор(ы): Я. М. Малаховски, А. А. Шалыто
Дата: 07.02.2010
В работе рассматриваются вопросы реализации на функциональных языках программирования событийных структурных конечных автоматов, используемых в автоматном программировании. На примерах показаны решения, имеющие преимущества перед реализациями на императивных языках программирования.
).

V>Вернемся к нашему подходу. ... Т.е. отделив в явном виде ф-ии вычисления след. состояния от собственно шага обновления состояния, мы можем добиться уникального в плане надежности качества — устойчивости к исключениям. ... В итоге, мы отказываемся еще от одной полезной практики, под названием "let it fail".

Интересный момент, но не пойму, какое это имеет отношение к обсуждаемым материям.

V>Обрати внимание на изящное решение популярной проблемы читателей/писателей, получаемое вместе с транзакционностью, когда мы стадию вычисления следующего состояния отделили от операции по его обновлению.

да, изящно.

V>Почему же функциональщики так жужжат о вреде смешения парадигм? ... Бери цифровую электронику. Это почти ООП (КОП в чистом виде) — интерфейсы и их реализации. И никто не страдает, что на одной плате есть как "чистые" цифровые ф-ии, так и россыпь автоматов.

Дык в ФП автоматы сплошь и рядом. Те же функции можно рассматривать как автоматы. Ленивость — автомат. Никто не страдает что свиду чистые функции являются фактически автоматами.

S>>Я бы сказал что знаком с китом, а не владею.


V>Не скромничай. Создание делегата по нестатическому методу — это всегда замыкание, еще со времен первого дотнета. А ты наверняка делегатов насоздавал за свою практику уже немало.


конечно насоздавал. Но владение китом не приравнивается к использованию делегатов. Даже не рядом. Все равно что говорить о владении ООП человеком, написавшему Console.WriteLine("hello world") на том основании что строка есть объект


S>>В шарпе — да. Куда сложнее на C++ без 0x, с которым приходится иметь дело.


V>Дык, а boost:bind? А старые добрые std::bind1st, std::bind2nd? Та же фигня. А слоты и сигналы QT?

boost-а и QT нет в текущем проекте, а std::bind*** покрывает довольно мало сценариев.

S>>Мне довольно удобно. неудобно как раз видеть решение в ФП виде и адаптировать его к ООП.


V>Наверно, от образа мыслей зависит. По мне ФП хорошо, пока мы производим вычисления, и плохо, когда нам результат этого вычисления надо куда-то девать. Монада IO в Хаскеле как раз помечает те места, где "чистое ФП" умывает руки.

Да, но при совмещении техник (при отказе от матаппарата ФП) эти места становятся недостойными внимания.

S>>ООП ведь не запрещает анализ!


V>Ни одна методология не запрещает. Мое ИМХО о том, что ООП поощряет начинать сразу с квадратиков.

Да. Если в программе должно выстрелить ружье, то в ООП программе появляются риски возникновения квадратиков "ружье", "стрелковое оружие", "оружие", "оружие с курком", "оружие с магазином" и т.п. Причем процесс этот довольно занимательный

S>>Дело в том, что код становится плохочитаемым не сам по себе, а в процессе изменений. И тут все-таки нужен рефакторинг, желательно в тот момент, когда код модифицирован, т.к. он только что прочитан и детали свежи.


V>Это в конкретном месте детали свежи. А если имеем несколько накопленных TODO, то можно попытаться обозреть проблему чуть более со стороны. И часто бывает так, что удовлетворяя один из них, можно удовлетворить целую пачку. В общем, перед решением любой задачи, желательно как можно больше вводных/требований. Хотя, каждый случай уникальный, понятно, и универсальных советов тут нет. Совет "рефакторить сразу" так же далек от универсальности.


Мне кажется что это особенности именно ООП рефакторинга, т.к. один и тот же объект (а то и в разных состояниях) встречается в различных местах кода. Изменяя какой-то аспект поведения объекта, либо его члены, приходится думать, а как это повлияет на код в другом месте. Особенно заметно при нарушениях SRP. И действительно, рефакторить такие места нужно представляя все сценарии использования объекта, а не местячково.
Re[12]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 11:49
Оценка:
Здравствуйте, samius, Вы писали:

V>>У функции нет собственного поведения, т.е. функциональности, зависящей от состояния, вот и все отличие.

S>Не совсем так. поведение функции может зависеть от состояния извне, переданного аргументом. Ключевое отличие — внутри или снаружи. Но и это отличие тает при упоминании о том что состояние передается неявно через this. Остается совсем незначительная деталь, отделяющая чистую функцию от метода объекта — функция не может менять внутреннюю память аргумента. (Уверен, ты все это знаешь. Я просто описываю ракурс, под которым я вижу немалую схожесть функции и объекта.) В таком ракурсе объект, не изменяющий свое внутреннее состояние, отлично воспринимается в виде функции и наоборот. Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.

Какие паттерны из ООП не перенесут иммутабельности ?
Re[11]: Почему объектно-ориентированное программирование про
От: samius Япония http://sams-tricks.blogspot.com
Дата: 24.02.11 12:07
Оценка:
Здравствуйте, Ikemefula, Вы писали:

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


S>>Я немного не об этом. Вот возьмем некий алгебраический тип и функцию, которая принимает его и возвращает новый экземпляр. Можно трактовать этот процесс по Кею следующим образом: экземпляру АТД отправляем сообщение (передаем его функции) и получаем результат сообщения (новый АТД). Естественно, что традиционному ООП это поперек горла. Но в рамках Кея ФП и ООПК(ООП по Кею) можно в каком-то роде совмещать. Это мое предположение, и я без понятия как к этому отнесся бы сам Кей.


I>Традиционному ООП это никак поперек горла быть не может

Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.

S>>В моей практике TODO имеют меньшие приоритеты чем issue в трэкере, потому плодятся как кролики. Стараюсь рефакторить сразу.


I>Любой код имеет свой цикл жизни. Рефакторинг удлинняет этот цикл жизни. Но сделать бесконечным просто не получится. Ну и издержки по вермени/деньгами никто не отменял. В конечном итоге становится проще выбросить хотя бы некоторые части и написать их заново.

Конечно и так бывает. Хоть это уже технически рефакторингом не называется, но все еще относится к обсуждаемым материям. Можно например назвать общим словом "улучшайзинг". А можно смотреть на рефакторинг чуть шире, чем того требует определение. Ведь целью рефакторинга не является сохранение функциональности само по себе. Иногда нужно и ломать, что бы на том месте строить что-то новое.
Re[13]: Почему объектно-ориентированное программирование про
От: samius Япония http://sams-tricks.blogspot.com
Дата: 24.02.11 12:10
Оценка:
Здравствуйте, Ikemefula, Вы писали:

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


S>>Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.


I>Какие паттерны из ООП не перенесут иммутабельности ?

например Iterator, Observer, State
Re[12]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 12:42
Оценка:
Здравствуйте, samius, Вы писали:

I>>Традиционному ООП это никак поперек горла быть не может

S>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.

При чем здесь замена ПМ полиморфизмом ?
Re[14]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 12:44
Оценка:
Здравствуйте, samius, Вы писали:

S>>>Между делом в ООП нигде не сказано что объекты обязаны обладать изменяемым состоянием, хотя и многие ООП паттерны не перенесут иммутабельности.


I>>Какие паттерны из ООП не перенесут иммутабельности ?

S>например Iterator, Observer, State

Переносят

yield break на первые два а для State не обязательно хранить ссылку
Re[13]: Почему объектно-ориентированное программирование про
От: samius Япония http://sams-tricks.blogspot.com
Дата: 24.02.11 12:53
Оценка:
Здравствуйте, Ikemefula, Вы писали:

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


I>>>Традиционному ООП это никак поперек горла быть не может

S>>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.

I>При чем здесь замена ПМ полиморфизмом ?

притом что type test не кошерен по ООП
Re[30]: Почему объектно-ориентированное программирование про
От: vdimas Россия  
Дата: 24.02.11 12:53
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>Соответственно никакого разделения состояния быть не может — декомпозиция проведена, а состояние где было там и осталось.


V>>Все ясно. Что есть по твоему "состояние"?


I>Элементарно — персистед данные.


А ссылка на другой объект в это понятие входит?


I>Принципиально. Состояния может и не быть, а зависимость будет в любом случае.


Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.


I>Вот посмотри внимательно ан мои примеры, я ажно дважды показал разбиение сложного решения на две части. И там и там разбиение по функциональному признаку.


Еще раз крупными буквами — не обязательно, коль декоратор после переработки объектов использует такую функциональность, которая после декомпозиции не нужна в исходном Doer. Давай ты уже сосредоточишься на этом моменте. Бо надоело.

I>>>Ога, сделать жосткую зависимость от другого класса


V>>Уточни, какая именно зависимость. Т.е. подставь сюда идентификаторы: X --> Y.




Хм, я же попросил, во избежание подобного копирования всего кода, конкретно указать зависимую пару (или пары). Ты не справился.

В общем, тебе стоит показать, что сия зависимость не идет в исходном коде по условию задачи. Ты же сам сказал, что присутствует некий дополнительный игрок — еще один класс, который мы не можем изменять. Будь добр, подкорректируй свой пример с учетом этого, и только потом покажи список лишних зависимостей, через простое перечисление, которые я ввел, в сравнении с твоим уточненным примером.


I>>>Опаньки, щас ты снова заговорил про связанность


V>>Знакомое слово услышал? Дык, а конкретные детали декомпозиции я из каких, по-твоему, соображений совершаю?


I>Ранее ты вещал про состояние


Невнимателен. Вещалось про наиболее значимую метрику, которая отражает степень связанности методов объекта с его собственным состоянием.


I>Уже давно было дадено это "локальное ТЗ".


Ладно, попахивает непрошибаемостью и незамутненностью сознания. Если ты не хочешь проработать собственный пример, с учетом собственных дополнений, давай договоримся прикрыть эту лавочку.


I>Адаптер это паттерн более древний, чем ООП


Черт. А фасад? А фабрика с одним методом тогда что? А почему в ФП не рассматривают эти приемы, как отдельные паттерны? Эх коллега, напряг бы что ли, кой чего... Может, в ФП не делают разницы от того, что наличие единственной ф-ии без описания ролей каждого из ее аргументов и истории её создания не позволит восстановить/распознать все происходящее за кулисами? Ведь по сигнатуре "SomeObj func(int arg)" никогда не скажешь, адаптер это, или фабрика.


V>>Дык, это у тебя зависимость от какого-то базового класса (упомянутого устно), и от явно заданного типа IDoer.


I>Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.


Вот надо поменьше говорить, побольше делать. В исходном примере можно было уже сто раз показать свой "особый случай", введя тот самый пресловутый некий класс, о котором так долго говорили большевики (С), и наличие которого для тебя является "элементарным и очевидным". Нам ты пока мест предлагаешь просто поверить тебе на слово. Не прокатит. Ближе к делу! Нарисуй еще раз.


V>>С состоянием и поведением! Иначе это не объект, а просто юзерский тип, описанный ср-вами ООП-языка.


I>Это в с++ тбе надо искать состояние.


Ваш сын еще и курит. А тигру в зоопарке мясо не докладывают.
Re[15]: Почему объектно-ориентированное программирование про
От: samius Япония http://sams-tricks.blogspot.com
Дата: 24.02.11 12:56
Оценка:
Здравствуйте, Ikemefula, Вы писали:

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


I>>>Какие паттерны из ООП не перенесут иммутабельности ?

S>>например Iterator, Observer, State

I>Переносят


I>yield break на первые два

можно подробнее?

I> а для State не обязательно хранить ссылку

в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.
Re[31]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 13:50
Оценка:
Здравствуйте, vdimas, Вы писали:

I>>Элементарно — персистед данные.


V>А ссылка на другой объект в это понятие входит?


Если персистед, то да. Если нет — то нет

I>>Принципиально. Состояния может и не быть, а зависимость будет в любом случае.


V>Чем обеспечивается зависимость? Впрочем, это тот же вопрос, что и предыдущий. Мои наихудшие подозрения оправдались.


Я уже внятно ответил на этот вопрос в твоем же коде — http://rsdn.ru/forum/philosophy/4171506.1.aspx
Автор: Ikemefula
Дата: 24.02.11


Что бы продолжить разговор про депенденси, ответь сначала вот на этот вопрос http://rsdn.ru/forum/philosophy/4171487.1.aspx
Автор: Ikemefula
Дата: 24.02.11


Походу, код показать ты не в состоянии

V>Хм, я же попросил, во избежание подобного копирования всего кода, конкретно указать зависимую пару (или пары). Ты не справился.


Прочесть коммент болдом ты не в состоянии ? Надо было сразу сказать

V>В общем, тебе стоит показать, что сия зависимость не идет в исходном коде по условию задачи. Ты же сам сказал, что присутствует некий дополнительный игрок — еще один класс, который мы не можем изменять. Будь добр, подкорректируй свой пример с учетом этого, и только потом покажи список лишних зависимостей, через простое перечисление, которые я ввел, в сравнении с твоим уточненным примером.


Я показал всё что необходимо.

I>>Адаптер это паттерн более древний, чем ООП


V>Черт. А фасад? А фабрика с одним методом тогда что? А почему в ФП не рассматривают эти приемы, как отдельные паттерны?


ФП это другой уровень

I>>Враньё. Я говорил совсем друго. Про базовый клас ты выдумал. В очередной раз скипнул, ибо похоже ты уже сам поверил в свое вранье.


V>Вот надо поменьше говорить, побольше делать. В исходном примере можно было уже сто раз показать свой "особый случай", введя тот самый пресловутый некий класс, о котором так долго говорили большевики (С),


Ты сам о нем говоришь. А я показал все что необходимо.

>и наличие которого для тебя является "элементарным и очевидным". Нам ты пока мест предлагаешь просто поверить тебе на слово. Не прокатит. Ближе к делу! Нарисуй еще раз.


есть фреймворк для рендеринга изображения. в нем реализованы различные генераторы изображения. каждая такая рисовалка должена реализовать интерфейс IRender(=IDoer) с единственным иметодом void Render(Context ctx); кроме этого есть еще рисовалки реализованые в проекте.

необходимо расширить возможности этого фреймворка диагностикой, валидацией, отладкой и тд

задача 1 — замерить время выполнения некоторых реализаций IRender — любых, как своих так и встроеных. Почему нельзя замерить через профайлер — нужны данные по продакшну, а не по дебагу
задача 2 — параллельно с генерацией изображения записывать генерацию в текстовом виде для валидации, диагностики, отладки
задача 3 — некоторые генераторы косячат. надо подавить их артефакты без перепеисывания. например перед вызовом генератора установить некоторые значения в контексте, а по окончанию вернуть значения назад.
задача 4 — необходимо иметь возможность включать-выключать некоторые генераторы, например при рендеринге на бумагу или экран
задача 5 — необходимо иметь возможность делать отрисовку по требованию, т.е. вместо изображения генерируются команды отрисовки примитивов, который потом можно выполнить в другом фреймворке.

в моем решении ненужно модифицировать ни генераторы, не фреймворк, вообще ничего нужно только сделать один декоратор на каждую задачу.

при этом для задач 1,2,3 и 4 декоторатору вообще не надо ничего знать ни про базовый, ни про Сontext.

1 использует StopWatch и Logger
2 использует логгер
3 использует контекст
4 ничего вообще не использует — у тебя вроятно фантазия не позволит представить такое

и только 5й использует кое какие методы из базового класса и класса Context

покажи внятное, тестируемое решение. если не можешь, объясни внятно, чего тебе не хватает.
Re[14]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 13:53
Оценка:
Здравствуйте, samius, Вы писали:

S>>>Оно фактически призывает воспользоваться OCP и заменить ПМ полиморфизмом, предусмотрев дальнейшее расширение иерархии и размазав логику работы метода по разным классам/файлам, а то и прикрутить какойнибудь TemplateMethod.


I>>При чем здесь замена ПМ полиморфизмом ?

S>притом что type test не кошерен по ООП

Это Страуструп так сказал ?
Re[16]: Почему объектно-ориентированное программирование про
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.02.11 13:54
Оценка:
Здравствуйте, samius, Вы писали:

I>>yield break на первые два

S>можно подробнее?

yield return разумеется

I>> а для State не обязательно хранить ссылку

S>в смысле состояние? Да, необязательно хранить ее внутри объекта. Но это уже будет что-то вроде автоматов в хаскеле, к паттерну State не имеющих отношения совершенно.

к тому паттерну что в Гоф, если трактовать исключительно буквально, отношения иметь не будет. А если посмотреть на назначение, обязанности и тд, получается тот же state
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.