1. C# / Говнокод #11733

    +123

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    static void Main() {
        Random random = new Random();
        ...
        int n1 = notations[random.Next(max)];
        int n2 = notations[random.Next(max)]; // дублирование кода!
        ....
        //исправлено на
        int n1 = notations[random.Next(max)];
        int n2 = n1;
    }

    Запостил: vistefan, 09 Сентября 2012

    Комментарии (86) RSS

    • great fix!
      Ответить
    • напомнило как я давече одному программисту нового поколения пытался объяснить что такое рандом (или зачем нужен seed). через пол часа безуспешных объяснений написал простой рандом для демонстрации - типа (x*a + b)%max - на что он мне тут же дал ответ что это не рандом, т.к. он видит реализацию и числа функция выдает совсем неслучайные.

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

      неисповедимы пути рандомов.
      Ответить
      • > числа функция выдает совсем неслучайные
        Ну поэтому эти числа и называются псевдослучайными.
        Ответить
        • это первое что я сказал ему и что пытался объяснить. без особого успеха.

          типа: почему они псевдо?! они ведь на самом деле случайные и не предсказуемые!
          Ответить
    • Плохой из него рефакторщик. Нужно было выкинуть нафиг переменную n2, и отрефакторить все ее вхождения на n1. ;)
      Ответить
    • показать все, что скрытоПлохой из него рефакторщик. Нужно было удалить нафиг переменную n2 и заменить все ее вхождения на n1.
      Ответить
      • Ну вот, стоит не покрасить фразу в зеленый цвет, как начинают минусовать ;)

        UPD: А тьфу. Это за даблпост. Сорри. Инет лагал. Думал один раз запостил.
        Ответить
        • +5, -5, годно.
          Ответить
          • +7, -7, ровно идут.
            Ответить
            • +10, -10, ждём 100 лет до переполнения, когда оба станут нулями.
              Ответить
              • Внезапно -8 +12. Какая сволочь не проминусовала? =)
                Ответить
                • Я подровнял ситуацию: -9 +11
                  Ответить
                  • Выровнял
                    Ответить
                    • Бухгалтер родился.
                      Ответить
                      • Тут проблема в том, что для того, чтобы одну цифру уменьшить, а другую увеличить, интуиция стремится нажать кнопки с разных сторон, а надо нажимать с одной, ну и наоборот, соответственно, видимо, отсюда и перекосы.
                        Ответить
                    • Мэм родился.
                      Ответить
                      • тогда уж "родилась"
                        Ответить
                        • родители думали, что родится мальчик, а родился я (ц)
                          Ответить
                          • И как назвали?
                            Заонанировали уже использования знака копирайта в таком уродливом виде, да ещё и не к месту.
                            Ответить
                            • (надев фуражку капитана) Мэм

                              ага, чтобы вы не дайбох подумали, что это я про себя )
                              Ответить
                            • > И как назвали?
                              Люсидфокс же.

                              > использования знака копирайта
                              Провослабный знак для цитаты - (q), жаль, не стандартизуют.
                              Что-то типа ⓠ.
                              Ответить
        • Это не даблпост. Строки не совпадают.
          Ответить
        • 5 за и 20 против равняется -16
          Видимо код проектировался с участием Чурова...

          Пруфпик: http://rghost.ru/40288588.view
          Ответить
          • Это не бага, это вмешательство злостных одминов, в данном случае Люра http://govnokod.ru/11733#comment153298
            Наведите курсор вот сюда, что бы убедиться:
            http://govnokod.ru/1#comment3
            Ответить
    • А вы предложите ему в цикле отобразить значения random.Next(max),
      а после, ознакомиться с
      https://ru.wikipedia.org/wiki/Генератор_псевдослучайных_чисел
      Ответить
    • Хах, бывает
      Ответить
    • Раз код работает, то не лезь туда с "оптимизациями".

      >static void Main()
      Подозрительно.
      Ответить
    • Самое смешное, что человек видимо на автопилоте это воспринял.
      Сам код уже реализован несколько располагающе к таким выводам (что идет дубликат кода), потому что код действительно визуально воспринимается как дубликат и только random выдает все хитросплетения коварства автора.

      Требовалось добавить комментарий о том, берем два рандомных значения, пусть это и комментарий капитана, но зато остановило бы от подобных правок, тех кто читает код на автопилоте :).
      Ответить
      • Чтобы такого не происходило, нужно вместо двух переменных n1,n2 создавать коллекцию vector<int> (ну что там у этих ... есть). И заполнять её в цикле. Тогда любой программист с РГМ ничего не заметит :D (j/k)
        Ответить
        • РГМ - "рукожопие головного мозга" видимо... ну не рефакторинг же.

          А на самом деле - ну каким надо быть идиотом, чтобы изменять вызов функций, не ознакомившись с тем, имеют ли они побочный эффект?

          Так и до такого маразма недалеко:
          // оригинал
          write(s);
          write(s);
          
          // ну и накуя тут два write'а?
          write(s);
          Ответить
          • Именно рефакторинг ;)

            Две крайности: функция #11712 и РГМ.

            Один из симптомов воспаления рефакторинга в заплаточной форме -- пренебрежение документацией.
            Ответить
        • Нет, тут хватило бы комментария. Не нужно усложнять код просто так, если в этом нет необходимости. дело не в РГМ
          Ответить
      • Тут не комментарий требуется, а комментирующая переменная или комментирующий метод, говорящие, что берется случайный элемент.
        А в защиту рефакторинга скажу, что Фаулер что при рефакторинге, что при оптимизации архитектуры советовал понимать, где проходят границы текущей подсистемы, т.е., что мы можем ковырять, а что является внешним и может нести побочные эффекты. Даже не залезая в доки и другой код ясно, что Random - вне подсистемы. Может быть, notations[что-то] тоже вне подсистемы.
        Ответить
        • Всё это разговоры в пользу нищих.
          Исправление коснулось внутренней структуры кода: было две разных переменных -- стало две одинаковых.

          Вопрос о том, что нужно читать документацию к коду, с которым работаете, НИКАКОГО отношения к Фаулеру не имеет.
          Ответить
          • > Исправление коснулось внутренней структуры кода
            Исправление изменило побочные эффекты кода - поэтому оно ну никак не могло остаться внутренним для подсистемы.

            > Вопрос о том, что нужно читать документацию к коду
            И желательно ее еще и писать, хотя лень ;)
            Ответить
            • Мы знаем, что при прочих равных функция может выдавать новые значения только потому, что мы знаем, что random имеет особую структуру вызовы с побочным эффектом.
              Внешнее тут вообще ни при чём: контракты соблюдены, сторонних делегатов в main не передавалось.
              К тому же... Random внутренний объект. Notations не изменялся.

              По сути это заведомо гомоморфизм внутрь идеала, где random выдаёт всегда два подряд одинаковых числа. Код не изменился ВООБЩЕ!
              Ответить
              • > это заведомо гомоморфизм внутрь идеала, где random...

                Вы всегда говорите так много умных слов, сочетание которых превращается в неведомую ту самую.
                Кстати, в каких книжках по ПО нынче пишут про "точки инверсии"?
                Ответить
          • По отношению к приведенному куску кода метод у random и индексатор у notations внешние.
            Я не сказал, что не надо читать доки.
            Надо стараться не просто не вызывать побочных эффектов у внешних подсистем. Надо стараться видеть, где у тебя границы проходят, чтобы, с одной стороны, минимизировать число вызовов между границами, с другой стороны, и не изменять вызовы так смело, без изучения внутренностей других подсистем.
            А Фаулера вспомнил, потому что тут упоминали рефакторинг и потому что как раз у Фаулера была мысль, что при первом анализе чужой реализации надо смотреть на интенсивность взаимодействия отдельных подсистем.

            Претензия к автору кода должна быть не
            - Почему ты меняешь работу с Random, не прочитав доки по Random? Ты что, не знаешь, как работает Random?
            а более адекватная и универсальная
            - Ты же видишь, что Random это что-то внешнее, почему не изучил его работу?
            Ответить
            • Внутри main существует некоторый алгоритм. Какой-то там, не знаю какой. У него нет предусловий. Возможно у него есть некоторые постусловия, но они по прежнему выполнены. Random заведомо внутренний объект, потому его вызовы не скажутся на внешнем поведении. Да это и всё равно, контракт по-прежнему выполнен, так как Random остаётся верным объектом. Notations, если вы полагаете, что он внешний, не изменился.
              О каком влиянии на внешнее можно говорить?
              Ответить
              • По отношению к приведенным кускам кода:
                1) этот же random может вызываться и в других строках
                2) индексатор у notations - это метод и в зависимости от реализации может вносить изменения
                Ответить
                • Вызовы Random не могут нарушить контракта Random. В этом вся суть класса как алгебры или категории. Любая операция над Random оставляет его корректным. Можно два, три, пять раз вызвать методы.
                  Из Main Random выйдет корректным. А внешний код не имеет права делать никаких предположений о том, как вызывался Random в Main. Тоже самое относится и к notations. Есть контракт Notations? Он соблюдён? Какие вопросы?!

                  А вот если Notations требует, чтобы его дважды вызывали (квадратные скобки могут быть вызваны только парами, например), то он и должен соответствующий контракт предоставлять.
                  Ответить
                  • var random = new Random();
                                var max = 10000;
                    
                                //обычно числа разные и все работает
                                var n1 = random.Next(max);
                                var n2 = random.Next(max);
                                var n3 = random.Next(max);
                                var n4 = random.Next(max);
                    
                                var x = 1.0 / (n1 - n2);
                                var y = 1.0 / (n2 - n3);
                                var z = 1.0 / (n3 - n4);

                    var random = new Random();
                                var max = 10000;
                    
                                //обычно числа разные и все работает
                                var sameShit = random.Next(max);
                                var n1 = sameShit;
                                var n2 = sameShit;
                                var n3 = random.Next(max);
                                var n4 = random.Next(max);
                    
                                var x = 1.0 / (n1 - n2);
                                var y = 1.0 / (n2 - n3);
                                var z = 1.0 / (n3 - n4);
                    Ответить
                    • Либо, для вашего алгоритма вполне допустимо деление на ноль.
                      Либо, существует доверенный контракт внутри алгоритма (тесная связь, неделимая часть, критическая область и т.п.).
                      Либо, вы запрограммировали алгоритм с ошибкой.
                      Ответить
                      • Нет-нет, пожалуйста, в терминах контрактов повторите свое утверждение, что изменение этих двух строчек работы с random ни на что не влияет.
                        Ответить
                        • Выше это и написано.
                          Либо у вас допустимо деление на ноль и ничего не изменилось.
                          Либо у вас неделимый кусок и вы неверно запрограммировали алгоритм.
                          Либо у вас существует предусловие на строчку var x = 1.0 / (n1-n2), которое формальное отсутствует, то есть ваш алгоритм неверно запрограммирован.

                          Из неверного можно получить ЧТО УГОДНО.
                          Ответить
                          • Т.е., изменение этих двух строчек не внесло изменений? ОК.
                            Ответить
                  • public int this[int index]
                            {
                                get
                                {
                                    //в следующей версии будет недельное кэширование
                                    return LoadFromHoduras(index);
                                }
                            }
                    Ответить
                    • А дельное кеширование запрограммировать никак? (j/k)

                      Либо потребителю всё равно, что там недельное кеширование, либо это описано в документации.

                      Повторяю: если человек не читает документации к коду, то может произойти ВСЁ ЧТО УГОДНО. С таким же успехом можно заменить вызов + на - и удивляться.
                      Ответить
                      • Нет, лучше повторите, что notation[index] не содержит побочных эффектов.
                        Ответить
                        • Вы где увидели, что я написал, что notation[] не содержит побочных эффектов?
                          Вы читать умеете?
                          Я ясно написал, что notation предоставил контракт [], следовательно я в праве использовать его. А если, по какой-то причине, это не так, значит и контракт был бы соответствующий.

                          Или опять мы падаем в дыру неверно запрограммированного кода поставщика. Тогда может быть что угодно.
                          Ответить
                          • >Вы где увидели, что я написал, что notation[] не содержит побочных эффектов?
                            >Notations, если вы полагаете, что он внешний, не изменился.
                            Ответить
                            • Да, вероятно слова "не изменился", не ясно описывают ситуацию.
                              Notation остался корректным. Пригодным для дальнейшего использования. Я не заменял контракт в переменной notations.
                              Ответить
                      • Что это у вас за фишка новая "(j/k)"?
                        Гей-сленг? http://tinyurl.com/cnstaa9
                        Ответить
                        • http://www.urbandictionary.com/define.php?term=j%2Fk
                          Ответить
                          • черт
                            даже после этой ссылки мой мозг не может не ассоциировать сочетание jk с матаном, тензорами и прочей ненужной херней
                            Ответить
                            • А у меня j/k ассоциируется с JK триггером ;)
                              Ответить
                              • я и забыл даже, что такое есть
                                схемота совсем не напрягала, хоть и была серьезным предметом
                                Ответить
                              • В urban dictionary, оказывается, ещё и r.s. и c/d есть.
                                Ответить
                              • j/k = jkjkjk = ололол
                                Чисто мои умозаключения. Может я и не прав.
                                Да, но у меня тоже с JK триггером ассоциируется.
                                Ответить
                                • Который John Kennedy переключал
                                  Ответить
                                  • Да, и его можно вспомнить, только он JFK.
                                    И про него даже была игра.
                                    Ответить
                        • Просто пропущены буквы e и r, очевидно же.
                          Ответить
                  • Я, конечно, нуб и ламер, но у меня возникает стойкое ощущение что вы уходите в формализм в ущерб здравому смыслу.
                    Ответить
                    • По-моему мнению из формализма в "здравый смысл" легче попасть, чем обратно.
                      А большинство проблем программирования, на мой взгляд, проистекают из того, что "опопсев", программирование лишилось качественного формального представления. Если в алгоритмике дела ещё сложились, то в управлении алгоритмами беда... ООП тому наглядный пример. Недостаток формального -- одна из центральных проблем. Слишком сильно люди тянули за ниточку "ближе к реальности". Да вот беда, программа по прежнему не может оперировать императивами, ей нужна хорошая формализация. И мы проектируем по "здравому смыслу", а конструируем согласно формальному. Вроде бы как архитектор дом нарисовал весь разэдакий, а конструктор потом глядит на это дело и не понимает, как пятый этаж может висеть в воздухе...
                      Ответить
                      • Формализм != формализация.
                        Поясню на примере: часто звучит рекомендация разбивать на составляющие методы, занимающие больше одного экрана. Если неразумно применять эту рекомендацию при рефакторинге, может получиться намного хуже чем было, хотя формально она будет соблюдена.
                        В рассматриваемом случае достаточно общего понимания что делает код (выбирает два случайных элемента), чтобы оставить всё как есть.
                        Я не отрицаю существования пограничных случаев, где выбор того или иного варианта реализации становится практически субъективным. Но здесь и сейчас как раз всё просто.
                        Ответить
              • > Возможно у него есть некоторые постусловия, но они по прежнему выполнены.

                А постусловие то было. "В n1 и n2 лежат 2 псевдослучайных числа (маловероятно, что одинаковых)". И его нарушили подобным рефакторингом.
                Ответить
                • Я на C# никогда реальные приложения не программировал, но, насколько мне известно, C#, также как и C++ , подчиняется формализму классической логики и формальным постусловием "маловероятно" быть не может.
                  Кроме того, "более вероятно", что n1 и n2 внутренние переменные алгоритма Main, и никто никогда не будет обращать внимание на то, как именно они получены (являются ли он псевдослучайными, например) и равны ли они друг другу.
                  Ответить
                  • Вы не правы, и я, как ОП, если хотите, могу снять вуаль загадочности с кода, и описать более подробно его происхождение и назначение.
                    Ответить
                  • К примеру возьмем код:
                    do {
                       n1 = random.Next(max);
                       n2 = random.Next(max);
                    } while (n1 != n2);

                    ГПСЧ редко выдает два одинаковых числа подряд (но может, и выдает!). Именно поэтому я и пишу "маловероятно", а не "никогда". Вот тут этот маловероятный случай прекрасно отбрасывается, и код работает.

                    Если же нарушить инвариант "маловероятности совпадений n1 и n2", превратив его в "n1 всегда такое же, как n2", код внезапно перестанет работать.

                    > подчиняется формализму классической логики
                    С тех пор, как программа способна обмениваться данными с внешним миром, никакой формальной логике она уже не подчиняется.
                    Ответить
                    • В вашем коде нет "маловероятности". Есть точное несовпадение. Я могу написать так:
                      n1 = someCallToGetInt();
                      n2 = n1+1;

                      Никаких вероятностей не нужно, чтобы выйти из цикла. Я выхожу с вероятностью 1.

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

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

                      Речь не идёт о том, что алгоритм не изменится. Изменится, возможно. Речь идёт о том, что проблемы, связанные с изменением этого куска проистекают не из того, что кто-то неправильно оценил "внешние" и "внутреннее" у делегата Main, а из того, что "прежде чем что-то поколебать, его нужно изучить". Нельзя использовать что-либо, тем паче изменять, если вы не знаете, как конкретно оно работает.

                      Если у функции Main хотя бы есть предположительный контракт из пустоты в пустоту, то у куска кода из двух строк вообще никакого явного контракта нет! А значит там может быть что угодно! Прежде, чем рубить, нужно ознакомиться с работой всех входящих элементов да и всего алгоритма.
                      Ответить
                      • Ты, interesting, несёшь хуйню, выдавая её за умные слова. (Это я ещё не упомянул, что ты гомосексуалист.)
                        Единственное, что верно в твоём посте - это фраза (хоть и капитанская)
                        > прежде чем что-то поколебать, его нужно изучить
                        Но во-первых ты сам противоречишь себе. Во-вторых ты говоришь с собеседниками в спорящей манере. Именно в спорящей. Но если бы ты действительно осознавал, что
                        > прежде чем что-то поколебать, его нужно изучить
                        ты бы понял, что все комментаторы в этом треде об этом и говорят.
                        Более того, сам факт того, что человек запостил это здесь, говорит он это понял.
                        Ответить
                      • > Есть точное несовпадение.
                        Согласен, есть. После выхода из цикла. Контракт всего цикла в целом - выдать 2 различных числа.

                        > В вашем коде нет "маловероятности".
                        Есть. Внутри цикла. ГПСЧ с небольшой но ненулевой вероятностью может выдать два одинаковых числа подряд. Чем это противоречит логике? Хорошо, я могу провести анализ конкретного ГПСЧ и написать, что в 3155 случаях из 368126387612 он выдаст одинаковые числа два раза подряд. Но зачем это делать, если можно указать, что данный факт "маловероятен, но пренебречь им нельзя"?

                        P.S. Тем более, что конкретную реализацию ГПСЧ я не знаю, но теория вероятности (если считать выхлоп генератора нормально распределенным), подсказывает, что вероятность невелика. Не нужно везде пихать формализмы. Во многих ситуациях достаточно здравого смысла.
                        Ответить
                        • Речь изначально шла именно о том, что формально рефакторинг прошёл успешно. Но с точки зрения здравого смысла -- нет. А причина не в том, что существуют некие формальные правила Фаулера, которые не выполнил программист, а более общий принцип: перед тем как перепаять телевизор, прочти принципиальную схему. А вот Фаулер здесь как раз и ни при чём.
                          Ответить
                    • Вообще с куском кода из двух строк, где явного делегирования нет, всё расплывчато.
                      То есть, кажется, что у этого куска контракт такой: без предварительных условий получить два int.

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

                      Это, кстати, имеет отношение к вопросу о разбиении большой функции на малые. Такое разбиение требует поиска внутреннего контракта между частями алгоритма. Весьма неочевидный процесс...
                      Ответить
                      • > числа не могут быть равными для корректного продолжения алгоритма
                        В коде, который привёл bormand, числа как раз-таки должны быть равными для выхода из цикла, lol.
                        Вы какую-то ерунду несёте, извиняюсь. Про контракты и весьма неочевидные процессы.
                        Ответить
                        • Да, это действительно так.
                          Не вчитался в код bormand.
                          Но это не имеет отношения к делу.
                          Ответить
                          • Да, согласен, n1 != n2 вместо n1 == n2 в данном случае просто опечатка/недодумка, отношения к делу не имеет.
                            Ответить
                        • > В коде, который привёл bormand, числа как раз-таки должны быть равными для выхода из цикла
                          ОМГ, я там написал n1 != n2... Вот так вот второпях писать код, и не тестировать его.
                          Ответить

    Добавить комментарий