Здравствуйте, __kot2, Вы писали:
IT>>Есть пример кода, который использует стандартный класс, который нельзя расширять. Нужно этот код переписать в 10 строк. Продемонстрируй мастер класс. __>откуда такое странное нельзя? кто запрещает-то? это незаконно, чтоли?
Запрещает Microsoft. Это код из стандартной библиотеки.
__>я сначала пишу код так, как если бы я выразил его словами
Это твои личные проблемы. Я может тоже так делаю, но и это мои личные проблемы. Давай по существу.
__>то есть вообще-то это обход дерева — tree_traversal __>или в раскрытом виде — лямбда на ноде и рекурсивно вызов для дочерних нодов. __>это и называется — ф-ия делает одну вещь. она обходит дерево. все остальное не относится к обходу дерева и не должно быть в этой ф-ии, чего бы мы с деревом не делали. и она не должна называться visit, transform или там do, чтобы не занимапться гаданиями на тему что же там реально внутри проихсодит
Не важно как это назвать. Важно, что тебе придётся доработать исходный класс, добавить в каждый нод по виртуальному методу. Скорее всего не по одному, т.к. кроме обхода дерева нужно ещё уметь его модифицировать, прерывать обход и т.п., т.е. сценарии обхода могут быть сильно разными.
В принцмпе, для самодельных деревьев я так и делаю. Но здесь ситуация не та.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, __kot2, Вы писали:
__>что такое "дополнительные свойства datetime" ? я без понятия. расчет релятивистких эффектов? марсианские сутки? сериализация? форматирование? поддержка времени хищника? название ни о чем не говорит.
Имя класса DateTimeExtensions мне говорит о том, что там лежат extension methods для DateTime. Для меня это вполне достаточная гранулярность.
__>а алгоритм побуквенно переписан из древнего писания или имеет какие-то вполне разумные части, типа, расчета credit score или поправка на семейное положение? этот алгоритм можно записать текстом так, чтобы его прочитал и с первого раза понял любой человек? или там просто в столбик строчки типа __>exptr2 += dev_thrillx(20, rack, grad_fix) * e + 8 * cutted_value/2 __>и для понимания значения их, нужно сидеть и весь день тупить в экран, ходить, выяснять, что там за phred и почему там стоит 8 ?
Это всё к чему? Куда-то мы, кажется мне, движемся в никуда...
Здравствуйте, IT, Вы писали: IT>Не важно как это назвать. Важно, что тебе придётся доработать исходный класс, добавить в каждый нод по виртуальному методу. Скорее всего не по одному, т.к. кроме обхода дерева нужно ещё уметь его модифицировать, прерывать обход и т.п., т.е. сценарии обхода могут быть сильно разными.
когда мы не хотим модифицировать исходный класс у нас всегда есть минимум два варианта получить нужное — делегировать к нему или наследоваться от него
Здравствуйте, MozgC, Вы писали: MC>Имя класса DateTimeExtensions мне говорит о том, что там лежат extension methods для DateTime. Для меня это вполне достаточная гранулярность.
а если я туда захочу положить код конверсии указателя солнечных часов во время и наоборот, это тоже можно extensions назвать?
со всякими хелперами и экстеншенсами проблема в том, что или можно назвать все. вот у нас есть number и есть пиксел на экране. любая программа это просто набор pixel и number extensions и helpers. весь джаваскрипт это, например, просто html extensions
вот мы взяли некие намберс, с помощью вспомогательных методов провели некие вычисления и с помощью методов расширений пикселов отобразили это на экране. логично? логично. но нифига не понятно. вот у нас есть код, который для человека расчитывает, например, прибавку к зарплате с учетом неиспользованных выходных, льгот, налогов или даже просто високосного года. я вот без понятия в каком хелпере-экстеншенсе искать подобный код — у user, у datetime (почему бы holidays не сделать расширением datetime например) у taxes (который можно сделать частью просто math? ) или снова в datetime, если разговор идет про високосный год. чаще всего вообще, когда программист понимает, что вроде как никуда оно не идет, он берет и пихает его в common). как-то в одном проекте видел common килобайт на 100
Здравствуйте, __kot2, Вы писали:
__>когда мы не хотим модифицировать исходный класс у нас всегда есть минимум два варианта получить нужное — делегировать к нему или наследоваться от него
Наследоваться не получится, т.к. не мы создаём его экземпляры. Делегировать хоть обделегируйся, но рано или поздно мы всё равно придём к тому же самому switch.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали: IT>Наследоваться не получится, т.к. не мы создаём его экземпляры. Делегировать хоть обделегируйся, но рано или поздно мы всё равно придём к тому же самому switch.
вообще не понимаю в чем проблема сделать UnaryExpression и BinaryExpression который будет реализовывать чисто виртуальный метод sub_expressions и выдавать соотв-но их.
или, чтобы, для перфоманса, не создавать временного списка, можно for_every_subexpression прямо соб-но его виртуальным мембером и сделать
аа, похоже понял — такие кривые экземпляры генерируются где-то внутри и нам придется перегенерировать все дерево выражений, если мы хотим работать с ним удобно. то есть основная проблема в том, что в мс придумали архитектуру с которой невыносимо работать. ну, чего ж тут удивительного. либо мы создаем дерево-враппер и работаем по-человечески, либо так криво со свичами, как говорится, в заданном стиле. хотя переименовать пару методов все равно стоит, хотя бы для того, чтобы понятно было где дерево, где его обход, а где код обработки какого рода операций
Здравствуйте, К Тёте, Вы писали:
КТ>Если нет верификатора, то (quickchek и иже с ним): КТ>- тесты должны описывать спецификацию, а не работу кода КТ>- тесты должны автогенерировать большой набор данных согласно спецификации КТ>- тесты должны проверять, соответсвует ли работа кода спецификации
Спецификацию на генератор парсеров с восстановлением после ошибок в студию.
Причем такую чтобы можно было реализовать код работающий быстрее чем может заметить пользователь.
После чего покажи, как по ней сгенерировать тестовые грамматики для генератора парсеров.
Потом сгенерировать сломанные исходники.
После чего оценить результат восстановления с точки зрения человека.
КТ>В итоге такие тесты выявят проблемы как в коде, так и в спецификации. Понятное дело, что даже такое не гарантирует 100% доказательство, но это лучше, чем вручную написанные тесты на ограниченном наборе данных, описывающие работу кода.
Только где же такую спецификацию взять?
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
WH>Спецификацию на генератор парсеров генератора парсеров.
У тебя профессиональная деформация.
КТ>>В итоге такие тесты выявят проблемы как в коде, так и в спецификации. Понятное дело, что даже такое не гарантирует 100% доказательство, но это лучше, чем вручную написанные тесты на ограниченном наборе данных, описывающие работу кода. WH>Только где же такую спецификацию взять?
Когда нет — придумывать. Если невозможно придумать, то — увы. Но я в жизни не поверю, что весь код состоит из функций, которые невозможно описать, как они работают. Для тех, что описуемы, тесты должны покрывать описание, а не то, как код работает. Например, какой-нибудь код, который убирает дубликаты из дерева разбора. Эти деревья можно нагенерить тоннами и проверить код на бОльшем количестве вариантов, чем assert(remove_duplicates([a, b, a]) == [a, b]).
Здравствуйте, К Тёте, Вы писали: КТ>Когда нет — придумывать. Если невозможно придумать, то — увы. Но я в жизни не поверю, что весь код состоит из функций, которые невозможно описать, как они работают. Для тех, что описуемы, тесты должны покрывать описание, а не то, как код работает. Например, какой-нибудь код, который убирает дубликаты из дерева разбора. Эти деревья можно нагенерить тоннами и проверить код на бОльшем количестве вариантов, чем assert(remove_duplicates([a, b, a]) == [a, b]).
в алгоритмах есть можно сказать "точки разрыва" — когда поведение меняется. то есть есть ф-ия, например, которая число печатает. переход от одной цифры к двум — такая "тока разрыва непрерывности решения". да, мы можем нагенерировать тонну, там, списков для проверки правильно работы убирания дубликатов, но разумнее специфицировать это примерно так:
[] -> [] // это спецификация на "невалидные данные"
[a] -> [a] // на данные, которые не нужно обрабатывать
[a, a] -> [a] // простейший пример
[a, a, a] -> [a] // а то вдруг там иф будет стоять, который пару схлопнет, а тройку нет
[a, b, a] -> [a, b] // дубликат, стоящий неподряд
[b, a, b, a] -> [b, a] // два дубликата неподряд
[a, b, c, b] -> [a, b, c] // убираем не первую букву (а то в остальных тестах она у нас че-то первая стоит)
минимальный код, который будет проходить эти тесты, должен будет убирать дубликаты по-нормальному
кстати, тест [b, a, b, a] -> [b, a] требует не просто убирания дубликатов, а сохранения их исходного порядка. что дает повод нам задуматься — а надо ли оно нам? мы-то знаем, что проще всего реализовать без сохранения порядка. вот почему мы вдруг от задачи "убрать дубликаты" вдруг перешли к вопросу "а сохранить ли порядок" и выяснили это не потом, когда что-то упало и мы в дебагере нашли, что порядок изменился и такие, Васе говорим "а че ты порядок-то поменял, олень? а он такой — "ды ну ты ж сам сказал, что дубликаты убрать надо, я и убрал, про порядок никто ниче не говорил"".
Здравствуйте, __kot2, Вы писали:
__>аа, похоже понял — такие кривые экземпляры генерируются где-то внутри и нам придется перегенерировать все дерево выражений,
Ты не архитектуру критикуй, а перепиши этот switch в 10 строк. Критиковать, особенно MS дело не хитрое. Мы все тут мега архитекторы даже не через одного, а по два раза каждый. Давай код.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали: IT>Ты не архитектуру критикуй, а перепиши этот switch в 10 строк. Критиковать, особенно MS дело не хитрое. Мы все тут мега архитекторы даже не через одного, а по два раза каждый. Давай код.
это сильно искусственный пример. предлагаешь поменять архитектуру с условием неизменности каких-то частей.
да, иногда есть причины написать говенный код, это одна из них — архитектура определена другим. но это не делает код на свичах менее гавенным. это просто его оправдывает. типа, у меня сломалась машину в лесу, я воткнул палку в двигатель, так и езжу.
Здравствуйте, К Тёте, Вы писали:
WH>>Спецификацию на генератор парсеров генератора парсеров. КТ>У тебя профессиональная деформация.
Нет. Это просто пример задачи, на которую невозможно написать спецификацию.
Просто по тому что до того, как задача решена неясно какое решение вообще может быть.
КТ>Когда нет — придумывать. Если невозможно придумать, то — увы. Но я в жизни не поверю, что весь код состоит из функций, которые невозможно описать, как они работают.
Ну так покажи класс. Напиши спецификацию на парсер нитры.
КТ>Для тех, что описуемы, тесты должны покрывать описание, а не то, как код работает. Например, какой-нибудь код, который убирает дубликаты из дерева разбора.
У меня в дереве разбора нет дубликатов.
Ибо сама возможность появления дубликатов ведёт к цепочке комбинаторных взрывов.
КТ>Эти деревья можно нагенерить тоннами и проверить код на бОльшем количестве вариантов, чем assert(remove_duplicates([a, b, a]) == [a, b]).
Ладно, поговорим о сферокониках.
Допустим исходные деревья мы нагенерировали.
А как генерировать то с чем сравнивать?
... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
Пусть это будет просто:
просто, как только можно,
но не проще.
(C) А. Эйнштейн
Здравствуйте, __kot2, Вы писали:
__>это сильно искусственный пример. предлагаешь поменять архитектуру с условием неизменности каких-то частей.
Это рабочий код. Всё, что тебе нужно сделать упаковать его в 10 строк.
__>да, иногда есть причины написать говенный код, это одна из них — архитектура определена другим. но это не делает код на свичах менее гавенным. это просто его оправдывает.
Началось. Говёный код, говёная архитектура... Обычно так говорят те, у кого говёный критерий говёности как и говёные предпочтения и не только по поводу размера функций.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали: IT>Здравствуйте, __kot2, Вы писали: __>>это сильно искусственный пример. предлагаешь поменять архитектуру с условием неизменности каких-то частей. IT>Это рабочий код. Всё, что тебе нужно сделать упаковать его в 10 строк.
не трогая остального кода, чтоли?
вот стоит человек, прыгает на одной ноге и пытается вилкой суп есть. я ему — ну ты бы ложку хоть взял и прыгать прекращай. а он — это у меня протез ножной заглючил, пытаюсь вот поесть приспособиться. говоришь ему сесть, тот отвечает, что ничего менять не может, хочет стоя. дурацкий способ есть? конечно же. можно ли его сделать нормальным, оставляя человека прыгать на одной ноге? нельзя.
Здравствуйте, __kot2, Вы писали:
IT>>Это рабочий код. Всё, что тебе нужно сделать упаковать его в 10 строк. __>не трогая остального кода, чтоли?
Это жизнь, чувак (c) Есть стандартный код, который нельзя трогать. И есть задача, которую нужно решать.
__>вот стоит человек, прыгает на одной ноге и пытается вилкой суп есть. я ему — ну ты бы ложку хоть взял и прыгать прекращай. а он — это у меня протез ножной заглючил, пытаюсь вот поесть приспособиться. говоришь ему сесть, тот отвечает, что ничего менять не может, хочет стоя. дурацкий способ есть? конечно же. можно ли его сделать нормальным, оставляя человека прыгать на одной ноге? нельзя.
В аналогиях ты не силён. Это уже понятно. Код давай. Всего каких-то 10 строк.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали: IT>В аналогиях ты не силён. Это уже понятно. Код давай. Всего каких-то 10 строк.
в смысле, помочь с удалением лишних переносов строк?
я же не собираюсь разводить демагогию о компилируемости и количестве строк, мне кажется все эти разговоры о выполнении формальностей безо всякого здравого смысла это удел вахтеров
КТ>>Для тех, что описуемы, тесты должны покрывать описание, а не то, как код работает. Например, какой-нибудь код, который убирает дубликаты из дерева разбора. WH>У меня в дереве разбора нет дубликатов. WH>Ибо сама возможность появления дубликатов ведёт к цепочке комбинаторных взрывов.
Блин. Это просто как пример был.
У вас там есть тесты на кеширование, на генерацию исключений, на рекурсию и т.п. Их вполне можно описывать.
КТ>>Эти деревья можно нагенерить тоннами и проверить код на бОльшем количестве вариантов, чем assert(remove_duplicates([a, b, a]) == [a, b]). WH>Ладно, поговорим о сферокониках. WH>Допустим исходные деревья мы нагенерировали. WH>А как генерировать то с чем сравнивать?
Это — на самом деле самое сложное в написании тестов с Quickcheck'ом В случае с парсерами и генераторами вполне может вылиться в создании парсера дважды (что, естественно, лучше не делать).
Для многих функций, работающих с деревьями разбора эквивалентной моделью в тестах могут быть списки/массивы.
Грубо говоря, например есть функция, удаляющая из дерева «мертвые узлы» (на которые никто не ссылается) или те же дупликаты. Генерится дерево с мертвыми узлами для кода и из этих же элементов генерится массив для сравнения. Тестируемый код удаляет узлы из дерева, тест — из массива. Потом сравнивается наличие узлов в дереве и в массиве.
В зависимости от того, как реализована функция удаления, такой тест может быть:
— малополезен, если сама функция достаточно простая
— полезен, если функция занимается каким-то дополнительным анализом или там хитрым сравнением каких-либо свойств. Потому что тест может нагененрировать деревья произвольной сложности с гарантированным присутсвием таких вот мертвых узлов. И выявить странные пограничные случаи, которые проявляются не на remove_dead_nodes([a,b,c]), а на remove_dead_nodes([a, [b, [[c]]]]]), которые ручками в тесте никто никогда не напишет.
Повторю, что такие тесты, понятное дело:
— все равно не дают 100%-гарантию
— не всегда легко написать (скорее наоборот, нелегко, особенно если нет большого опыта в написании таких тестов, у меня, например, нет)
— не всегда можно написать
__>в алгоритмах есть можно сказать "точки разрыва" — когда поведение меняется. то есть есть ф-ия, например, которая число печатает. переход от одной цифры к двум — такая "тока разрыва непрерывности решения". да, мы можем нагенерировать тонну, там, списков для проверки правильно работы убирания дубликатов, но разумнее специфицировать это примерно так:
__>[] -> [] // это спецификация на "невалидные данные" __>[a] -> [a] // на данные, которые не нужно обрабатывать __>[a, a] -> [a] // простейший пример __>[a, a, a] -> [a] // а то вдруг там иф будет стоять, который пару схлопнет, а тройку нет __>[a, b, a] -> [a, b] // дубликат, стоящий неподряд __>[b, a, b, a] -> [b, a] // два дубликата неподряд __>[a, b, c, b] -> [a, b, c] // убираем не первую букву (а то в остальных тестах она у нас че-то первая стоит)
__>минимальный код, который будет проходить эти тесты, должен будет убирать дубликаты по-нормальному
Это все идеальная утопическая ситуация. На практике все гораздо сложнее. Ты, например, в своей «спецификации» не описал толпу вариантов, которые, в зависимости от того, насколько сложная функция уборки дупликатов, могут сработать, а могут не сработать.
На quiviq'овских воркшопах приводят другие интересные примеры из реальных ситуаций, когда программисты забывают тестировать пограничные значения.
Например, код сериализации для SMS-gateway'я, который вылетал на данных размером, кратных 2^8, хотя все тесты проходили. Ну, как тесты. Там был тест типа твоей «спецификации». Три строчки типа
IT>Опять лишь штампы, догмы и наклеивания ярлыков. Демагогия, короче.
IT>Вот тебе метод на 300 строк. Иди и сделай его в 30 короче.
Ну, тут ничего не надо делать.
— Код уже разбит на функции, причем довольно мелкие
— Некоторые case'ы и функции можно сделать чуть более читаемыми, если есть pattern-matching (но в C# его нет, так что увы)
Здравствуйте, dosik, Вы писали:
D>Т.е. улучшая читабельность кода мы уменьшаем производительность системы.
На производительность сейчас многим наплевать. В читабельность улучшается только по мнению Мартина, который, наверное, просто не программировал на Smalltalk. Там обработка сообщений компактная донельзя, в результате при чтении чужого когда возникает проблема найти требуемую функциональность, которая где-то в проекте, но не здесь...