А как вы пишете сложный код?
От: Sinix  
Дата: 10.03.11 04:14
Оценка: 19 (3)
Hello 2 all!

Чуть-чуть введения: бывший коллега попросил рассказать, как быть с кодом, про который сам толком не можешь сказать — что он должен делать и как именно.

Парой месяцев раньше сам бы развёл руками и послал бы читать 2ю главу из Framework Design Guidelines (FDG), но тут нежданно припёрло и мне самому пришлось написать гору кода именно в таких условиях Чтобы не терялось, запощу тут.

Зачастую проблема даже не в том, что не знаешь, как подступиться к решению, а в том, что не знаешь, как решить задачу _лучше_. Есть решение со средней асимптотикой O(log N), есть O(n..N^2). Можно писать императивщину, можно сразу замахнуться на чисто-ФП решение. Что лучше? Что будет лучше в перспективе? Какие будут грабли?

Когда я в очередной раз оказался в роли Буриданова осла, решил попробовать на практике рекомендацию из FDG:

Framework Design Principle
Frameworks must be designed starting from a set of usage scenarios and code samples implementing these scenarios.


Итак, во что же это вылилось на практике?


1. Подготовка

Понадобится как минимум 1 дополнительный проект — для написания собственно сценариев использования. Поскольку у меня в основных проектах выше крыши продакшн-кода, там особенно не разгуляешься. Пришлось создавать ещё один проект — для прототипов.

Раньше я бы запихнул прототип в один проект с тестами и потерял бы очень важный бонус: когда тесты живут отдельно, они почти стопроцентно имитирует реальные сценарии использования. Если у вас нет никакого доступа к internal-member-ам и прочим внутренностям и вам неудобно использовать прототип, то, очевидно, реальный код тоже не будет отличаться умом и сообразительностью хорошим юзабилити.

Опустим неприятный момент придумывания сценариев использования, их написание и создание компилируемого кода-заглушки в сборке прототипов — всё это подробно описано во 2й главе FDG и кучу раз пережёвано в каждой TDD-дискуссии. Отмечу только, что код сценариев использования фактически является кодом интеграционных тестов (_не_ юнит-тестов) и что было бы глупо этим не воспользоваться


2. Пишем прототип

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

У нас уже есть интеграционные тесты, они же — сценарии использования. Остаётся убедиться, что решение корректно в целом. Конечно, можно использовать TDD. Увы, у меня он хорошо работает только при стабильной внутренней архитектуре кода, когда уже известно, что и как тестировать. У нас сейчас полностью обратная ситуация: мы хоть как-то определились с тем, что должен делать код, а вот как именно решать задачу — пока неизвестно.

Поэтому лично я предпочитаю писать ассерты прямо по месту использования — полный аналог if-then-throw, которыми напичкан фреймворк. Вся разница в том, что вместо разнородного кода аля
if (index < 0 || index >= list.Count)
{
  throw new ArgumentOfRangeException("index", index, "Bla-bla-bla 1");
}
// ...
// Я тут слегка беру через край, но сложные ассерты действительно просто записать кучей способов.
if (!(i < 0) && !(index < list.Count)) 
{
  throw new ArgumentOfRangeException("Bla-bla-bla 2!");
}

мы имеем
CollectionsCode.ValidIndex(index, "index", list);


Часть ассертов будет публичным контрактом прототипа: проверять корректность передаваемых параметров, допустимость вызова метода в текущем состоянии и т.п. Но большая часть ассертов (чем сложнее код — тем больше ассертов) будет заменять юнит-тесты и будет проверять инварианты — условия, который никогда не должны нарушаться в идеальном мире в правильно написанном коде. Разумеется, такие дебаг-ассерты можно пометить [Conditional("DEBUG")] и не волноваться за производительность продакшн-кода.


3. Переписываем прототип.

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

К сожалению, я не настолько идеален, и выход этапа 2 представляет из себя адскую мешанину ad-hoc-хелперов и комментариев "TODO:" и "REFINE:". Зато в голове у меня наконец-то откладывается главное: как можно решить нашу задачу, и как будет выглядеть код, решающий эту задачу.

Поэтому я делаю 3 вещи:
1. Пишу тест производительности прототипа;
2. Переписываю прототип набело, сохраняя все ассерты;
3. Прогоняю на готовом коде сценарии использования и тесты производительности. Исправляю и повторяю до получения приемлемых результатов.

Закончим маленьким примером. Прототип:
      SortedSet<int> changedIndexes = new SortedSet<int>();
      int oldCount = count;
      int newCount = changes[undoToEditOrdinal].TrackingValuesCount;

      for (int i = undoFromEditOrdinal; i >= undoToEditOrdinal; i--)
      {
        SwapValuesAndRemoveIndexes(changes[i], newCount, changedIndexes);
      }
      currentChangeSetOrdinal = undoToEditOrdinal - 1;
      count = newCount;

переписанный код:
      ChangeSetRange<T> undoRange = GetUndoRange(undoFromEditKey, undoToEditKey);
      DebugAssertState(currentEditKey == undoFromEditKey.EditManager.CurrentEditKey);

      foreach (ChangeSet2<T> changeSet in undoRange)
      {
        changeSet.Undo(source);
      }
      undoRange.MoveTo(redoChanges, 0);

      currentEditKey = undoToEditKey.EditManager.PreviousEditKey(undoToEditKey);

Хоть результат и не блещет внутренней красотой — это не public api, и от него не требуется универсальность и переиспользуемость — но, по крайней мере, он отражает _намерения_ программиста куда лучше, чем предыдущий код.


Disclaimer-ы и ответы на незаданные вопросы

Во-первых, спасибо всем, кто всё ещё со мной

Во-вторых, основная цель поста — показать, как на практике пишется "сделай не-знаю-что"-код. Ключевое слово — на практике, т.е. всё вышеперечисленное работает как минимум у меня.

В-третьих, ни одна сверхздравая идея не будет работать без трезвого к ней отношения. Не надо писать прототип _всего_. Не надо слепо следовать написанному и обобщать до "у меня не работает — отстой" или "у нас сработало — мегакруто, будем использовать везде". Короче говоря, мозг в комплект не входит

Напоследок, пара заранее заготовленных отмазок:

1. А нельзя ли было написать сразу кусок кода #2 (опционально почеркав на бумажке) и не мучать клавиатуру, себя, окружающих и бедный интернет?
Нельзя. Загвоздка в том, что исходная задача выглядела классическим чёрным ящиком: известно, что на входе, известно, что на выходе, решай как тебе удобно, и нет, точно такую проблему тут раньше не решали. И всё, что известно о коде выше для public api — это
  editManager.Undo(fillDataEditKey);


2. Не пиши код, на который нет требований.
Я только за

3. Используй xDD (подставить нужное).
С радостью. Делитесь — как решаете такие задачи вы?

Комментарии, возражения и холивары — велкам
Re: А как вы пишете сложный код?
От: мыщъх США http://nezumi-lab.org
Дата: 10.03.11 04:37
Оценка: 20 (1) +2
Здравствуйте, Sinix, Вы писали:

S>Hello 2 all!


S>Первое, что надо держать в голове, когда пишешь сам прототип: "ты сейчас пишешь код на выброс".

S>Это значит — никакого рефакторинга для улучшения архитектуры, никаких оптимизаций, никаких универсальных всемогуторов.
S> Сейчас главное — написать код, который хоть как-то работает, убедиться, что он работает правильно,
я бы еще добавил -- прототип должен быть максимально гибким. в частности, сейчас я пишу высокоскоростной парсер, работающий с битыми входными данными by design. и пишу его... на 90% на регулярках. просто чтобы продемонстрировать принципиальную возможность работы с битыми данными, а так же заставить этот код работать, методично опробуя различные подходы. регулярки тормозят ужасно, но зато их легко модифицировать. а вот если реализовать эту же логику "руками" -- мы утратим гибкость.

если позволяют ресурсы, то прототип можно воздвигать на каком-то скриптовом языке (например, на питоне), потому как там реально быстро программировать. намного быстее, чем си. правда, прототип, действительно, будет на "выбор" и его придется переписывать заново на целевом языке.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Re: А как вы пишете сложный код?
От: Alexéy Sudáchen Чили  
Дата: 10.03.11 08:21
Оценка: +2
Ну в общем целом всё правильно, только вот отношение к коду странное. Ну то есть когда как делать непонятно это нормально. Точнее даже непонятно не как вообще делать, а какой способ выбрать. Оно очень часто так бывает, но что делать — вообще-то должно быть понятно. Даже когда цель 'cделать красиво' =).

Если человек не знает что должен делать его код или не представляет вообще ни одного способа каким образом код может это делать — он зря к компутеру подошёл. Лучше пойти погулять и подумать.

Реально прототип нужен шоб выбрать лучший способ или проверить что такой способ вообще реализуем. Может быть вообще на другом языке. Очень хорошо писать прототипы на Python'е.

И про код на выброс — это вопрос опыта. К примеру, я прототипы пишу очень часто, но то что доказало жизнеспособность легко трасформируется в продакшин. Даже если прототип на питоне, а конечный код на C/C++ — прототип это не только проверка реализуемости, но и референс реализация для проверки более сложного (рабочего) кода. Переписывать же код 'на бело' и 'с нуля' на том же языке =) Это не для меня. Ну о-о-о-чень ленивый. Просто надо понимать итеративность процесса. Не обязательно писать говнокод, можно просто писать только то что нужно сейчас, но не закрывать возможность реализовать что-то большее. Опять же Python для этого просто идельно подходит. Хотя это уже вопрос интуиции и опыта — не все могут просто сесть и совершенно естественно написать код, который легко будет менять/развивать.

Вот вчера писал прототип одной забавной фиговины, результат как раз-таки можно применять в пику деятельности коллег мыщЬха =) Я его практически в таком виде и выложу (в рекламных целях). Переписывания не требует. Другое дело что то что проверялось будет реализовано несколько иначе, в другом окружении и даже немного для другой цели =)

Ну и да, не люблю я это модное слово реФАКторинг. Само слово как бы намекает на созвучный процесс в отрицательном его смысле. Есть эволюция кода, программы, дизайна. Она естественна и не нуждается в каких либо искуственных методиках и насильственном процессе. Всё должно идти от реальных задач и условий работы этого кода, а не от папирусов с заветами =)
Re[2]: А как вы пишете сложный код?
От: Sinix  
Дата: 10.03.11 09:14
Оценка:
Здравствуйте, Alexéy Sudáchen, Вы писали:

AS>Если человек не знает что должен делать его код или не представляет вообще ни одного способа каким образом код может это делать — он зря к компутеру подошёл. Лучше пойти погулять и подумать.


Это чересчур радикально Я тоже так думал, до тех пор пока не столкнулся с задачей "на тебе условия, нужен такой-то результат, а как ты будешь делать и можно ли это сделать вообще — это науке неизвестно".

Самый простой пример — анализ скомпилированного кода на c#, нахождение сложных свойств (т.е с геттером/сеттером, отличным от return field|field = value) и выдача варнинга, если где-то в коде к полю обращаются в обход свойства. И, тут же парная задача — предупреждать, когда код использует простые свойства вместо того, чтобы обращаться к полям напрямую.

Даже если ограничиться полуофициальным Microsoft.CCI, задачу можно решить 2мя подходами — их визитором или анализом последовательности il-инструкций. Дальше — веселее:
— строить стековую state-машину или использовать RX (почти удалось)?
— как быть с багами (в визиторе есть специальные костыли, но кто ж знал?)?
— что делать, если придётся дополнить логику, например, пропускать проверку конструкторов или находить свойства — обёртки вокруг других свойств?
— что мы пропустили (например, индексаторы)?


Ещё недавний пример — http://www.rsdn.ru/forum/dotnet/4158148.aspx
Автор: Sinix
Дата: 15.02.11
. Если интересует, поищу описание этого квеста.

Наконец, в принципе нерешаемая "правильным" способом задача —
http://www.rsdn.ru/forum/dotnet/3775195.aspx
Автор: Sinix
Дата: 15.04.10

http://stackoverflow.com/questions/2651327/nested-multithread-operations-tracing
http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/e7cc41f0-9be5-4a3f-8fc9-5a3bfe6bd7f2/

Это только задачи, связанные непосредственно с используемыми инструментами. С бизнес-логикой всё ещё веселее.




AS>Реально прототип нужен шоб выбрать лучший способ или проверить что такой способ вообще реализуем. Может быть вообще на другом языке. Очень хорошо писать прототипы на Python'е.


Не, для реального кода нужен dogfooding — все потенциальные косяки должны вылавливаться, пока пишется прототип. Иначе какая от него польза?

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


Легко, но смысл идеи с прототипированием в том, чтобы _намеренно_ не писать продакшн код и не заморачиваться с кучей вещей, которые обязательны для продакшна: читаемостью, именованием, следованием FDG, понятной архитектурой, расширяемостью, простотой в использовании etc. Иначе написание прототипа превращается в "а тут документируем, тут строим иерархию наследования, тут добавляем поддержку config-файла, тут пишем костыли к wpf. Блин, всё непонятно! Рефакторить!".

Нет уж, мухи отдельно, котлеты — отдельно.

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




AS>Всё должно идти от реальных задач и условий работы этого кода, а не от папирусов с заветами =)

Ув. XopoSHiy эту мысль сформулировали гораздо лучше. Вот тут
Автор: XopoSHiy
Дата: 14.04.10
.
Re[3]: А как вы пишете сложный код?
От: Alexéy Sudáchen Чили  
Дата: 10.03.11 12:21
Оценка: +2
Здравствуйте, Sinix, Вы писали:

S>Это чересчур радикально Я тоже так думал, до тех пор пока не столкнулся с задачей "на тебе условия, нужен такой-то результат, а как ты будешь делать и можно ли это сделать вообще — это науке неизвестно".


У меня _ВСЕ_ задачи такого рода =) Большую часть времени я думаю, читаю, ковыряю отладчик и пишу маленькие но хитрые скрипты на питоне. Давно уже понял — пока я не знаю что именно я собираюсь делать, код писать бессмысленно.

Вы кстати зря смешиваете 'правильно' и качество кода. 'Правильно' вообще не бывает =), а качество кода оно хоть и оценивается субьективно но реально и сильно влияет на работу с кодом. ('Обьектиные' критерии качества кода — это вибратор для манагеров =))

S>Это только задачи, связанные непосредственно с используемыми инструментами. С бизнес-логикой всё ещё веселее.


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

S>Легко, но смысл идеи с прототипированием в том, чтобы _намеренно_ не писать продакшн код и не заморачиваться с кучей вещей, которые обязательны для продакшна: читаемостью, именованием, следованием FDG, понятной архитектурой, расширяемостью, простотой в использовании etc. Иначе написание прототипа превращается в "а тут документируем, тут строим иерархию наследования, тут добавляем поддержку config-файла, тут пишем костыли к wpf. Блин, всё непонятно! Рефакторить!".


Э... а почему бы не иметь привычку всегда писать читаемый код с нормальным именованием, понятной расширяемой архитектурой и не заморачиваться вещами, которые на данной конкретной итерации не нужны?! Как бы не совсем понятно зачем писать иначе. То есть по вашему если пишешь прототип, то это обязательно гвонокод?! Просто по тому что писать говнокод быстрее и легче. Да нифига подобного. Это иллюзия =) Кстати, коли вы так любите это слово, что таки в вашем понимании рефакторить?

Я повторюсь, но я действительно считаю что прототипы нужно писать для проверки работоспособности идеи. Собственно качество кода прототипа это критерий профессионализма программера, а не препятсвие которое мешает писать =) Так что прототип — это не говнокод на выброс, а просто быстро написанный код проверяющий конкретную идею. Зачем впадать в крайности мне совсем не понятно. Как для прототипа, так и для рабочего кода. ИМХО, но любой живой проект на каждой стадии своего развития, в каком-то смысле, прототип для следующей. И что на каждой стадии его переписывать с нуля?

AS>>Всё должно идти от реальных задач и условий работы этого кода, а не от папирусов с заветами =)

S>Ув. XopoSHiy эту мысль сформулировали гораздо лучше. Вот тут
Автор: XopoSHiy
Дата: 14.04.10
.


Ну да, хотя я немного о другом говорил =)))). Но можно и на примере GoF. GoF — это общеобразовательная литература. Не список рецептов, но терминология. Однако не зная внутренних механизмов дизайна невозможно понять почему шаблоны из GoF такие, какие они есть. Но эти механизмы по GoF особенно то и не понять. От народ и пишет декоратоы, фабрики и визитёры. Но _зачем_ они это делают — не понимают. Тут надо что-то типа книг/статей Боба Мартина читать.

Точно так же далеко не все любители рефакторить понимают зачем они это делают и что именно. Как следствие, сей рефакторинг превращается в утомительный процесс, который несовместим с прототипированием и применим только к продакшен коду. Что ИМХО есть бред сивой кобылы =)
Re: А как вы пишете сложный код?
От: WolfHound  
Дата: 10.03.11 12:32
Оценка: +1
Здравствуйте, Sinix, Вы писали:

Никак.
Если код получается сложным значит ты идешь не тем путем или используешь плохой инструмент.
Взять например ту задачу которую ты тут упомянул: editManager.Undo(fillDataEditKey);
Тебе говорили как свести решение к тривиальному но ты не послушал.
В результате тебе пришлось развести целую философию о том как писать сложный код.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: А как вы пишете сложный код?
От: Sinix  
Дата: 10.03.11 13:49
Оценка:
Здравствуйте, Alexéy Sudáchen, Вы писали:

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


С нормальным именованием — надо понимать, как код работает. Речь в посте — о ситуациях, когда в принципе непонятно, как подступиться к задаче и даже чёрканье карандашом не сильно помогает — в момент реализации тонны упущенных деталей убивают напрочь изначальную идею.

AS>Как бы не совсем понятно зачем писать иначе. То есть по вашему если пишешь прототип, то это обязательно гвонокод?!


Где я про это говорил? И кстати, найдите хоть один "говнокод" с моей стороны. Не только в этой теме — вообще на форуме. Давайте менять стиль дискуссии, тут всё-таки философия, а не КСВ

Поясню, что именно мне не нравится.

Я описал условия и во введении, и в disclaimer-е. Специально для вас привёл реальные случаи, когда сложность реализации превосходит концептуальную сложность и бесполезно решать задачу без написания рабочего кода.

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

Вы говорите, что всё — фигня, сводите тему к слегка другой задаче ("прототипы нужно писать для проверки работоспособности идеи"), добавляете утверждения, которых я не делал:

Просто по тому что писать говнокод быстрее и легче. Да нифига подобного. Это иллюзия =)

и долбестно их опровергаете. Мне это не нравится, срач разводить не хочется, поэтому пока что закругляюсь. Как бы то ни было, спасибо за участие!

AS>Однако не зная внутренних механизмов дизайна невозможно понять почему шаблоны из GoF такие, какие они есть. Но эти механизмы по GoF особенно то и не понять...

+1
Re[2]: А как вы пишете сложный код?
От: Sinix  
Дата: 10.03.11 14:17
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Если код получается сложным значит ты идешь не тем путем или используешь плохой инструмент.

Зачастую задачи, которые приходится решать, вообще слишком сложны для более-менее адекватной формализации. Или вообще нет адекватных средств для их решения. Примеры приводил тут
Автор: Sinix
Дата: 10.03.11
.

WH>Взять например ту задачу которую ты тут упомянул: editManager.Undo(fillDataEditKey);

WH>Тебе говорили как свести решение к тривиальному но ты не послушал.

Это про переход к immutable и взятие снапшотов?
Отвечал уже тут
Автор: Sinix
Дата: 15.01.11
, тут
Автор: Sinix
Дата: 15.01.11
и тут
Автор: Sinix
Дата: 15.01.11
. Ответных ответов не увидел

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

Во-первых, при таком подходе мы тратим в десятки раз больше памяти, чем надо.
Во-вторых, чтобы работал биндинг, список должен реализовать INotifyCollectionChanged. Для того, чтобы не обновлять всю коллекцию, нам потребуется динамически вычислять diff между снапшотами.

И на закуску — сценарий чуть посложнее: отслеживание изменений с последующим сохранением в базу. Разумеется, с топологической сортировкой всего графа — чтобы не нарушать constraints.

Поймите, бессмысленно писать фреймворк в ФП-style, если 100% пользовательского кода — императивщина.
Re[3]: А как вы пишете сложный код?
От: WolfHound  
Дата: 10.03.11 14:36
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Зачастую задачи, которые приходится решать, вообще слишком сложны для более-менее адекватной формализации. Или вообще нет адекватных средств для их решения. Примеры приводил тут
Автор: Sinix
Дата: 10.03.11
.

Ответ тут
Автор: hardcase
Дата: 09.03.11
и тут
Автор: Sinix
Дата: 09.03.11
.

S>Это про переход к immutable и взятие снапшотов?

S>Отвечал уже тут
Автор: Sinix
Дата: 15.01.11
, тут
Автор: Sinix
Дата: 15.01.11
и тут
Автор: Sinix
Дата: 15.01.11
. Ответных ответов не увидел

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

S>Во-первых, при таком подходе мы тратим в десятки раз больше памяти, чем надо.

Можно подумать у тебя все на святом духе держится и история память не жрет.

S>Во-вторых, чтобы работал биндинг, список должен реализовать INotifyCollectionChanged. Для того, чтобы не обновлять всю коллекцию, нам потребуется динамически вычислять diff между снапшотами.

Нет ту никаких проблем. Тем более что дифф ты получишь бсплатно.

S>И на закуску — сценарий чуть посложнее: отслеживание изменений с последующим сохранением в базу. Разумеется, с топологической сортировкой всего графа — чтобы не нарушать constraints.

Тяжолый ОРМ? Это само по себе сильно зря. В не зависимости от подхода.

S>Поймите, бессмысленно писать фреймворк в ФП-style, если 100% пользовательского кода — императивщина.

А может императивщина не нужна? Ты об этом не думал?
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: А как вы пишете сложный код?
От: Sinix  
Дата: 10.03.11 14:49
Оценка:
Здравствуйте, WolfHound, Вы писали:

S>>Во-первых, при таком подходе мы тратим в десятки раз больше памяти, чем надо.

WH>Можно подумать у тебя все на святом духе держится и история память не жрет.
Жрёт, но на порядок меньше — хранятся только изменённые элементы, а не весь список целиком. Вывод тестов могу найти в понедельник-вторник, но код пока что опубликовать не смогу

S>>Во-вторых, чтобы работал биндинг, список должен реализовать INotifyCollectionChanged. Для того, чтобы не обновлять всю коллекцию, нам потребуется динамически вычислять diff между снапшотами.

WH>Нет ту никаких проблем. Тем более что дифф ты получишь бсплатно.
Как? В состоянии один у нас [0,1,2,3,4], в состоянии 2 — [0,14,2,32,4]. Перебирать 2 списка и сравнивать попарно?
Кроме того, как быть с биндингами, с гридами и прочим UI? Там хош-не-хош надо реализовать IList+INotifyCollectionChanged и имитировать поведение изменяемых коллекций. То же самое относится к большей части существующего кода.

S>>И на закуску — сценарий чуть посложнее: отслеживание изменений с последующим сохранением в базу. Разумеется, с топологической сортировкой всего графа — чтобы не нарушать constraints.

WH>Тяжолый ОРМ? Это само по себе сильно зря. В не зависимости от подхода.
Не, скорее нечто ближе к датасету, но без его косяков.

S>>Поймите, бессмысленно писать фреймворк в ФП-style, если 100% пользовательского кода — императивщина.

WH>А может императивщина не нужна? Ты об этом не думал?
Думал, и (лично я) — не против. Осталось объяснить это всему мейнстриму.
Re[5]: А как вы пишете сложный код?
От: Alexéy Sudáchen Чили  
Дата: 10.03.11 15:26
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Я описал условия и во введении, и в disclaimer-е. Специально для вас привёл реальные случаи, когда сложность реализации превосходит концептуальную сложность и бесполезно решать задачу без написания рабочего кода.


Можно словами такой пример описать и желательно не представляющий из себя борьбу с инструментом? Я не пишу под .NET и чтобы понять проблему которую вы решаете мне сначала нужно разобраться в фреймворке и среде исполнения. Оно мне надо?! Я вообще с этим 'богатством' предпочитаю не связываться. FDG для меня вообще ничего не значащее сочитание букв.

S>Вы говорите, что всё — фигня, сводите тему к слегка другой задаче ("прототипы нужно писать для проверки работоспособности идеи"), добавляете утверждения, которых я не


Да это ФИГНЯ. Уж простите мой французкий.

Я выступаю против двух тезисов: 'прототип — это код на выброс' и 'можно что-то писать (прототипировать) на зная что должен делать код, который пишешь'. Первое признак излишка времени либо неумения писать код, второе — вообще бред. Не существует правильного и совершенного кода, любой код всего лишь прототип того чем он станет в слующей итерации. Вы же почему-то говорите о неком прототипе который выбрасывается (из за низкого качества код или несоответсвия стандартам или нучёта какой-то архитектуры), а проверенная идея пишется с нуля как совершенный код учитывающий всё на свете. А если не учитывающий, то чем он от прототипа то отличается? Живой код всегда пишется от состояния 'что-то работает' к состаянию 'делает всё что нужно с требуемыми характеристиками' и ни в одном состоянии не имеет заявки на совершенство.

ИМХО конечно, однако у меня действительно практически все задачи из разряда ХЗ как делать, так что я знаю о чём говорю.
Re: А как вы пишете сложный код?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 10.03.11 16:16
Оценка: 10 (1) +1
Здравствуйте, Sinix, Вы писали:

S>Комментарии, возражения и холивары — велкам


А что такое сложный код? Мне кажется, что тут можно придумать очень много самых разных задач, для которых нужен свой подход

Для одного кода я зарылся в MATLAB и там пробовал разные варианты. Когда нашел приемлемый --- закодировал идею почти на чистом C. Во втором случае просто начал с разработки разных тестов, где задания формировались в отдельном файле. Потом опустился на уровень процедур и функций, прикрутил логирование каждого шага, анализатор этих логов и копался в этом.
Re[2]: А как вы пишете сложный код?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 10.03.11 16:41
Оценка:
Здравствуйте, WolfHound, Вы писали:

WH>Если код получается сложным значит ты идешь не тем путем или используешь плохой инструмент.

WH>Взять например ту задачу которую ты тут упомянул: editManager.Undo(fillDataEditKey);

А можно взять другую задачу? Например, написать программу, которая бы играла в го в силу про-дана на одном ядре с контролем 30'+30". Каким тут путем идти, чтобы код получился простым?
Re[4]: А как вы пишете сложный код?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 10.03.11 16:43
Оценка: 1 (1)
Здравствуйте, Alexéy Sudáchen, Вы писали:

AS>У меня _ВСЕ_ задачи такого рода =) Большую часть времени я думаю, читаю, ковыряю отладчик и пишу маленькие но хитрые скрипты на питоне. Давно уже понял — пока я не знаю что именно я собираюсь делать, код писать бессмысленно.


У меня часто наоборот бывает. Начинаешь писать код, понимаешь, что собираешься сделать. А иначе можно до конца века видеть и размышлять, а всего в голове не удержишь
Re[2]: А как вы пишете сложный код?
От: Sinix  
Дата: 10.03.11 16:44
Оценка:
Здравствуйте, Mystic, Вы писали:

M>А что такое сложный код? Мне кажется, что тут можно придумать очень много самых разных задач, для которых нужен свой подход

Название топика не самое удачное, согласен
Re[3]: А как вы пишете сложный код?
От: WolfHound  
Дата: 10.03.11 17:10
Оценка:
Здравствуйте, Mystic, Вы писали:

M>А можно взять другую задачу? Например, написать программу, которая бы играла в го в силу про-дана на одном ядре с контролем 30'+30". Каким тут путем идти, чтобы код получился простым?

Напиши программу которая подбирает коллизию для SHA512 на одном ядре за пару секунд.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[5]: А как вы пишете сложный код?
От: WolfHound  
Дата: 10.03.11 17:10
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Жрёт, но на порядок меньше — хранятся только изменённые элементы, а не весь список целиком. Вывод тестов могу найти в понедельник-вторник, но код пока что опубликовать не смогу

Значит ты что-то не так делаешь.

S>Думал, и (лично я) — не против. Осталось объяснить это всему мейнстриму.

Короче бодаться с тобой в очередной раз мне лень.
Сойдемся на том что: Технологии менстрима заставляют писать неоправданно сложный код.
Я свой выбор сделал не в пользу этих технологий. Если комуто хочется жрать кактус то я отговоривать не буду. Мне лениво.
... << RSDN@Home 1.2.0 alpha 4 rev. 1472>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Re[4]: А как вы пишете сложный код?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 10.03.11 17:20
Оценка: +2
Здравствуйте, WolfHound, Вы писали:

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


M>>А можно взять другую задачу? Например, написать программу, которая бы играла в го в силу про-дана на одном ядре с контролем 30'+30". Каким тут путем идти, чтобы код получился простым?

WH>Напиши программу которая подбирает коллизию для SHA512 на одном ядре за пару секунд.

Ну я же не говорил, что

Если код получается сложным значит ты идешь не тем путем или используешь плохой инструмент.


Я вполне допускаю, что есть задачи, где от сложности кода уйти никуда нельзя, например, где сложность кода это прямое следствие сложности алгоритмов и самой задачи.
Re[2]: А как вы пишете сложный код?
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.03.11 19:04
Оценка: :))
Здравствуйте, мыщъх, Вы писали:

М>я бы еще добавил -- прототип должен быть максимально гибким. в частности, сейчас я пишу высокоскоростной парсер, работающий с битыми входными данными by design. и пишу его... на 90% на регулярках.


Жуть! Я бы в таком даже побоялся бы признаться. В прочем я бы таким и заниматься не стал бы.

М>просто чтобы продемонстрировать принципиальную возможность работы с битыми данными, а так же заставить этот код работать, методично опробуя различные подходы. регулярки тормозят ужасно, но зато их легко модифицировать. а вот если реализовать эту же логику "руками" -- мы утратим гибкость.


Руками? А почитать что-нить по теме парсеров не пробовал для начала? Не все задачи берутся методом замучивания.

Парсить регулярками — это из серии вырезать гланды через жопу автогеном.

М>если позволяют ресурсы, то прототип можно воздвигать на каком-то скриптовом языке (например, на питоне), потому как там реально быстро программировать. намного быстее, чем си. правда, прототип, действительно, будет на "выбор" и его придется переписывать заново на целевом языке.


Прототипы и делаются для того чтобы их выбрасывать (я правильно понял, что вместо "выбор" имелось в виду "выброс"?).
Так что это как раз не проблема. Проблема в том что в области парсинга ни регулярки, ни (тем более) скрипты не помощники.
И как раз "руками" тут получится наиболее гибко. Проблема в том, что при всех гибкости это будет и наиболее сложный вариант.

В общем, мой тебе совет. Возьми подходящий инструмент и сделай свой прототип. Подходящий интсрумент тут — это генератор парсеров. Я бы посоветовал бы взять наш Nemerle.Peg. Он грамматики любой сложности возьмет. Ну, а "битые входные данные" это ни что иное как более сложные грамматики. И PEG тут будет самым подходящим инструментом. В прочем, любой генератор парсеров будет лучше чем регулярки или ручное написание парсера.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: А как вы пишете сложный код?
От: VladD2 Российская Империя www.nemerle.org
Дата: 10.03.11 19:09
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Это про переход к immutable и взятие снапшотов?

S>Отвечал уже тут
Автор: Sinix
Дата: 15.01.11
, тут
Автор: Sinix
Дата: 15.01.11
и тут
Автор: Sinix
Дата: 15.01.11
. Ответных ответов не увидел


Ткнул на ссылки и увидел вполне вменяемые ответы. Может не хотел увидеть?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.