архімаггриб в Дарницькі печери
  • Коменты в обратном порядке

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

    Затем, что так будут читать те, кто уже ознакомился с предыдущими комментариями.
    Ваш К.О.

    Имхо, данный стиль комментов полный бред, но я давно понял, что на ДОУ бесполезно подымать эту тему.

    Имхо, потому и бесполезно, что в Вашей логике, мягко говоря, трещины и провалы

  • Ruby VS PHP

    Если мы в нем не можем этого чего-нибудь найти: то на это требуется как минимум явная реакция именно для этого хранилища.

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

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

    А ещё есть вопрос тестирования — на котором особенно явно, что поиск багов резко облегчается, если видим исключение, но не если проблема замолчена (тогда без пошагового отладчика фиг чего найдёшь).

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

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

    Разгадка проще: в документации явно указано что является false.

    В документации может быть задокументировано что угодно (например, что 0 и 3.1415926 являются False, а остальные значения — True). Вопрос в том, насколько такое поведение консистентно в общих рамках языка и средства. Понимание любой непустой строки как истинной, как в Python, консистентно с логикой языка, в котором неявная конверсия строки в число недопустима. Язык, в котором числа и строки смешаны до такой степени, что их нельзя отличить никакими средствами самого языка, но при этом 0.0 есть false, а «0.0» есть true — неконсистентен и поэтому ущербен. И сколько бы его авторы ни документировали этот подход — правильнее он от этого не станет.

  • Коменты в обратном порядке

    Да, но я чем дальше, тем меньше вижу пользы в этом. Особенно когда комментарий сводится, грубо говоря, к «нет, это неверно» и выплыл вверх за счёт пары десятков лайков: без контекста в нём нифига не понятно, а контекст тут не принято сохранять. Аналогичное есть, например, на RSDN, но там более традиционно сохраняется контекст и поэтому можно понять, о чём идёт речь.

    Только непонятна альтернатива. Может, сортировать ветки по скорингу и упорядочивать уже их?

    И ещё было бы полезно плоское представление (не тредами) с сортировкой по дате постинга — для ускорения перечитывания серьёзной темы.

  • Ruby VS PHP

    Дык это больше вопрос стиля.

    Если Вы ищете полный аналог, то «exists $a[$x]» заменяется на «x in a», или, в более старом стиле, «a.has_key(x)». Ловить этот через немедленный catch («except» в Питоне) смысла нет, код с прямым непроверяемым доступом («a[x]») рассчитан на то, что ошибки будут ловиться в общем случае и на другом уровне.
    Или же вместо этого пишется «r = a.get(x, None)», а затем «if r is not None:...» (тоже вариант, выгоднее в некоторых случаях).

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

    «Традиционная» область перла: «натащить из CPAN’а модулей, и побыстрому шонить наваять».

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

    В случае с Perl’ом я бы наверное предпочел чтобы всё что пишется в YAML было «строками».

    Ну вот мы поневоле пришли к этому. Потому что иначе просто не работало — умничало, когда не имеет права.

    Поэтому нет, если все так как вы говорите (я к JS не имею никакого отношения), то в JS таки «делают не совсем так».

    Я не вижу смысла сурово разделять их (JS с одной стороны, Perl, PHP с другой), потому что это всё проявления одной и той же болезни: наплевательство на типизацию.

    Вот ещё один пример проявления: в Perl в булевском контексте «0» — false, но «0.0» и «00» — true:

    $ perl -e 'print "true\n" if "0";'
    $ perl -e 'print "true\n" if "0.0";'
    true
    $ perl -e 'print "true\n" if "00";'
    true

    А разгадка всё та же — безблагодатность наплевательство на строгость типизации и попытка сэкономить объём кода на неявных эффектах, которые имеют смысл только для микрообъёмов кода, но не для существенного проекта...

  • Ruby VS PHP

    я еще раз повторюсь — вы приписали перлу и пшп то, чего нет

    Я «приписал» им неявную конверсию между числами и строками. Она, очевидно, есть.

    а по поводу конверсии — лично мне (после си) такой подход нравиться , код чистый от явных преобразований и лучше читается

    Он в разы хуже читается, потому что непонятно, что ожидать от каждой операции.

    «неожиданные эффекты» возникают обычно от быдлокода, так быдлокодера строгая типизация не остановит

    Она позволит тому, кто будет читать код, увидеть эту конверсию и оценить её необходимость и эффекты в этом конкретном месте. И не позволит замаскировать такие конверсии.

    В языках, где этот вопрос решён адекватно (например, в Go), даже конверсия между равномощными int и int32 запрещена, потому что первый — тип конкретной платформы, а второй — межплатформенный переносимый.

  • Ruby VS PHP

    Если по простому: «если с двумя скалярами вы делаете операцию как для строки(string) тогда мы их считаем строками, если как для чисел — тогда мы их считаем числами».

    Ну вот в Javascript вроде бы так и делают. ’-’ оно для чисел. А вот ’+’ оно и для чисел и для строк, и тогда начинает зависеть от приоритета: 5+"3″ это сложение чисел или строк?

    Но объясните мне всё-таки — конверсия в JSON/YAML/etc. скаляр, который может быть числом или строкой — это операция для числа или для строки?

    Но Perl вроде как и никогда не тащили во все дыры, а в традиционных для него областях вполне оправдано в приницпе-то.

    Простите, а какие области считать «традиционными»? Если считать «традиционной» областью задачу дополнить /bin/sh до логического завершения, а не оставлять концептуально дырявым, как решето (я не в смысле безопасности, а в смысле логической целостности) — то да, Perl на это хорошо ложится. Только тогда проблема, на кой нужен Perl5? Последним, который соответствовал именно этой задаче, был Perl4.

    А вот если мы переходим к языку, на котором пишутся крупные проекты — то надо многие вещи делать уже совершенно иначе. В частности, подход языка должен быть таким, что он не маскирует ошибки, а выявляет их. Например, в Python написав a[x], мы получаем исключение, если ключ x не существует; а чтобы явно получить пустое значение, надо писать a.get(x, None), и это явно привлекает внимание при анализе кода. В Perl, $a{x} даёт undef, если ключа нет, а для генерации исключения надо рисовать явную проверку с die, или вызывать специально написанную для этого функцию. И так с очень многими чертами языка и библиотеки. Чем толще и сложнее проект, тем больше язык с подобными умолчаниями и решениями за программиста мешает, а не помогает.

  • Ruby VS PHP

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

    С чем Вы не согласны?

  • Ruby VS PHP

    тщательнее надо быть

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

  • Ruby VS PHP

    Я и не говорил, что тот пример был про Perl. Вообще-то он был про Javascript.
    Но в названных языках сама по себе неявная конверсия между числами и строками — диверсия.
    У нас с ней был другой эффект — когда при экспорте правил телефонного раутинга из Perl через YAML префиксы, начинающиеся с 0, неожиданно потеряли этот 0, хотя передавались как строки. Оказалось, что из-за невозможности различить число и строку, YAML dumper пытался опознать это своими силами и ошибался. Лечением стал экспорт всего со спец-ключом dumper’а «экспортировать скаляры как строки даже если это числа» и делать конверсию уже по контексту на приёмной стороне.
    После этого случая я все языки, где типизация недостаточно жёсткая и возможна конверсия между числами и строками, строками и булевскими переменными и т.д., считаю шеллами-переростками и не воспринимаю их как языки для крупной разработки. Некоторые языки честно признают, что они шеллы-переростки, и отлично работают в этом смысле — например, Tcl. Некоторые признают и неплохо справляются, маскируясь под высокоуровневые — например, Perl. Но если такой язык в принципе не признаёт этот факт — то ему место на помойке.

    PHP в этом смысле вообще клинический случай — там у типизаций, сравнений и т.д. нет никакой логической согласованности ни с самим собой, ни с внешними концепциями, сплошные хаки и отклонения.

  • Ruby VS PHP

    Это проблема форума:) у меня всё сбалансировано.

  • Коменты в обратном порядке

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

    Как минимум 1) свежие вверху, 2) свежие внизу, 3) по скорингу (лучшие вверху)

  • Ruby VS PHP

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

    Смысл очень прост: явные блочные скобки принципиально нужны для того, чтобы быстро одним взглядом охватывать структуру, и не спотыкаться на проблемных случаях (как хрестоматийные множественные if-else в C и аналогах). Конкретная их реализация — {}, begin-end или отступами — уже не принципиальна, это дело вкусовщины конкретного языка. Меня устраивают все три, но меня не устраивает (а когда натыкаюсь на проблемы — бесит) кривой стиль, как в классическом Паскале (до Модулы) или в C с наследниками.

    Например, правильный стиль для if, с моей точки зрения, выглядит так (пример из SER):

    if (cond1) { body1 }
    elif (cond2) { body2 }
    else { body3 };
    

    Здесь неважно, elif, elsif, else if или как-то ещё, можно пропускать всё кроме блока if, но важно, что скобки ({}) обязательны вокруг тела блока под условием, и финальное ’;’ однозначно завершает разбор всей конструкции. За счёт минимального оверхеда (2-3 знака) мы получаем чёткость, ясность и однозначность, в отличие от сишных соплей.

    Не зря все практически известные стили кодирования требуют, что если под if/else/etc. что-то сложнее одного простого оператора, или в несколько строк — требуется ставить блочные скобки.

    В python — ООП «прикручено сбоку», и его тормозов можно избежать, зная как оно прикручено, если нужно, в Ruby — оно фундаментально.

    Не вижу принципиальной разницы, с учётом того, что на самом деле основные тормоза идут за счёт принципиально динамической (хоть и строгой) типизации. Это показал опыт Cython, который в основе есть Python с уточнением действий за счёт типизации переменных: основное ускорение возникает именно там.

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

    Підтримав: undefined pointer
  • Ruby VS PHP

    Типы надо всё время приводить

    И это правильно — язык с эффектами, когда 5-"3"==2, но 5+"3"==53 — очень стрёмный для разработки чего-то больше анимации одной страницы. Вообще, только группа Perl — PHP — Javascript (из массовых) позволяет такой бред, остальные используют значительно более строгую типизацию.

    Лично у меня ощущение, что в Украине даже Питон распространен сильнее Руби.

    Угу, и он однозначно перспективнее на сейчас. И, кстати, между ним и Ruby короче прыгать, если нужно, чем между Ruby и PHP.

  • Чего не дают в ВУЗе?

    Кажется, могу сформулировать, что мне не нравится во всей этой дискуссии: это выделение ВУЗа как отдельного периода в жизни, что в его течение — учатся, а после — работают.

    По-нормальному такая выделенная и централизованная учёба не должна останавливаться никогда. По крайней мере для работающих в IT.
    Пусть один день в неделю — но должна быть.
    У научных работников в СССР был раз в неделю «библиотечный день». (Не знаю, как с этим сейчас.)

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

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

  • Как скоро WinRT вытеснит

    Судя по этому обсуждению:
    www.rsdn.ru/...mp/4962327.flat
    ещё неизвестно, куда и как развернётся махина.

    (читал и плакал)

  • Вопросы к практикующим TDD

    Поведение должно было изменится, на что вы и написали тест, а оказалось что он проходит и без ваших изменений.

    Вы в курсе, что на один модуль/функцию/метод/etc. может быть много тестов, и что изменение требований не обязательно ломает их всех?

    Вы не в курсе что о чем таки говорите.

    Что я в курсе, говорит практика.

    Посему позволю себе наглость пропустить дальнейший текст и признать вас «правым во всем».

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

  • Вопросы к практикующим TDD

    Что-то я не особо понимаю вы за меня или за медведя? (За ТДД или против)

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

    В чем именно некорректность?

    В классическом TDD объявляется, что
    1) пишутся тесты до кода
    2) тесты должны быть проверены на то, что они не проходят
    3) пишется код для их удовлетворения.

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

    Чтобы допустить в принципе ситуацию, когда код меняется, надо допустить, если использовать правило «test first», что новые тесты соответствуют TDD, но старые — нет, часть тестов может работать и до новой разработки, и после. А это значит, что они уже нарушают этот принцип — их нельзя проверить на корректность той проверкой, что «тест до написания упал => он, вроде, правильный».

    Поэтому, или вы доверяете корректности уже существующих тестов согласно их коду, но тогда правило «сначала тест должен упасть» вообще теряет смысл, или вы вводите другие методы контроля корректности тестов (в моём случае это инверсии тестов, когда проверяется нарушение выходных данных при заведомых отклонениях входных данных). А в этом случае уже пофиг, были написаны тесты до или после: это вопрос административного контроля качества покрытия тестами, но не собственно их выполнения.

    Сначала написан код. Теперь пишем тест.
    На основании кода? Нет ибо тогда он не проверяет код,

    Чушь какая. Вот Вам пример кода:

    -spec(group_pc_repr(list({any(),list()})) -> list({any(),list()})).
    group_pc_repr(List) ->
        rec_group_pc_repr([], List).
    
    -spec(rec_group_pc_repr(list(), list({any(),list()})) -> list({any(),list()})).
    rec_group_pc_repr(Out, []) ->
        Out;
    rec_group_pc_repr(Out, [{Tag, List1}, {Tag, List2} | Rest]) ->
        rec_group_pc_repr(Out, [{Tag, List1 ++ List2} | Rest]);
    rec_group_pc_repr(Out, [{Tag, List} | Rest]) ->
        rec_group_pc_repr(Out ++ [{Tag, List}], Rest).
    

    А вот несколько тестов:

            {"rec_group_pc_repr() merge 3",
                ?_assertMatch(
                    [{k1,[a,b]},{k2,[c,d]}],
                    ?M:rec_group_pc_repr([],
                        [{k1,[a]},{k1,[b]},{k2,[c]},{k2,[d]}]))},
            {"rec_group_pc_repr() merge 4",
                ?_assertMatch(
                    [{k1,[a]},{k2,[b,c]},{k3,[d]}],
                    ?M:rec_group_pc_repr([],
                        [{k1,[a]},{k2,[b]},{k2,[c]},{k3,[d]}]))}
    

    И как же эти тесты, пардон, «описывают» код? Они фактически являются спецификацией пунктов поведения кода, как он должен вести себя на нескольких характерных ситуациях. (Тривиальные проверки типа пусто->пусто я здесь не показываю.)

    Если же Вы мне тут собрались рассказывать, что «проверкой» кода является то, что при его отсутствии тест показывает нарушение выполнения, то см. выше.
    Или представьте себе, что кто-то что-то нарушил в среде выполнения и код проверки (в данном случае _assertMatch) выдаёт всегда положительный результат. Что Ваша проверка тут покажет? Её удовлетворит любой код, при котором тестируемый метод вообще существует и, соответственно, его вызов не порождает исключения.

    и если код с ошибкой, то ошибка будет и в описании.

    Тест не делается под коду. Тест делается по тому, что он должен выполнять. Если у Вас такие сотрудники, что они в состоянии написать любую ересь, лишь бы она удовлетворила тест, и никто это не проверяет, то они Вам напишут, повторюсь, ровно код вида

    multiply(0, 0) -> 0;
    multiply(2, 0) -> 0;
    multiply(2, 2) -> 4.
    

    то есть удовлетворяющий заданные тесты и не более того.
    И таким сотрудникам — не место в нормальной конторе, а если их никто не поймал за руку на ревью — то и их ПМ’у.

    А если тесты пишутся по ожидаемому поведению, а код — для соответствия спецификации, то порядок написания кода и тестов не имеет значения. Лишь бы эта работа была выполнена.

    На основании спеки. Тест прошел — все классно. Не прошел — надо переписывать код. Вопрос: Накуя мы писали код?

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

    Код — это формальная запись некоторого процесса (в общем модели). Для того чтобы его (код) написать надо сформировать эту модель. Желательно сформировать в формализованном виде, как пример ТДД-тесты/БДД-спеки.

    Формализация в виде тестов даст ровно необходимость соответствия этим тестам и ничего сверх того.
    Имея «модель» в виде f(0,0)=0, f(2,2)=4, Вы даже не можете сказать, что требовалось — сложение или умножение, и тем более — какая точность, скорость, диапазон входных значений, и так далее. Поэтому тесты не заменят спецификацию выполняемого, и Ваше «желательно» непригодно для практической реализации.
    А если есть спецификация, то есть и потенциальная необходимость дополнить уже сделанное новыми тестами.

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

  • Вопросы к практикующим TDD

    Просто изменил что-либо в редакторе и тулза запускает тест, который покрывает код, в который внесены изменения.

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

  • Вопросы к практикующим TDD

    Архитектура чего? Всей системы или модуля?

    Каждого уровня. И системы, и модуля. Разумеется, на каком-то уровне сам термин «архитектура» начинает терять смысл, сводясь к очевидному.

    Всей системы если и появится, то не на первом шаге, прийдется упорно рефакторить.

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

    Ок 1 и 2 покрываем. А что не покрываем тестами?

    А почему Вы спрашиваете? Разве я писал, что что-то не покрываем?

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

    Тут у Вас сразу несколько сомнительных допущений. Давайте по порядку.

    Во-первых, откуда ожидать появление этой ветки? Почему она будет? Если она не нужна ни для какого требования спецификации, то ей нет причины вообще существовать. Если же она существует, то отрабатывает какой-то сценарий согласно спецификации, а значит, на неё наверняка будут тесты в составе первого пакета (BDD).

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

    Во-вторых, предположим, что есть какая-то ветка, которую не покрыли тестом. Почему тестеры и пользователи её не заметят (а потом кто-то один заметит)? Может, спецификация просто содержала ненужное?

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

    Снова же если исходить из «сначала тесты», то появление такой ветки практически не возможно

    Неверно. Оно было бы теоретически возможно, если бы следовали другому правилу — «пишите только тот код, который удовлетворяет тесты» (что само по себе — грубая ересь: писать надо тот код, который решает задачу по спецификации и является минимальным для удовлетворения теста, а иначе можно писать только кучу if-return для значений тестов). Но Вы это правило тут не упомянули, а упомянули зачем-то порядок тестов, который вообще это не решает. Можно написать вперёд тесты, потом код, а можно вперёд код, потом тесты — и код будет одинаковый, если программист в состоянии держать в голове задачу.

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

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

    Простите, у меня, видимо, другая практика. Я никогда до сих пор в явном виде не решал задачу «определить входы и выходы юнита», несмотря на то, что много лет «в системе». Прошу расшифровать это.

  • Вопросы к практикующим TDD

    по теме, похоже, нечего сказать?

    Я достаточно высказался по теме в предыдущих комментариях.

← Сtrl 1... 370371372373374375 Ctrl →