Re: Как не надо писать код
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.04.11 03:59
Оценка: 41 (5) +4
Здравствуйте, AlexNek, Вы писали:

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



public void WriteTransformation(ref byte[] buffer, ref int dataLength, WriteByteHandler writeByteHandler)
{
  if (writeByteHandler == null)
    return;
  if (dataLength < 0)
    throw new ArgumentOutOfRangeException("Data length should be non-negative", dataLength, "dataLength");
  if (buffer == null)
    buffer = new byte[0];
  if (dataLength > buffer.Length)
    throw new ArgumentOutOfRangeException("Data length should not exceed the buffer length", dataLength, "dataLength");

  var newBuffer = new byte[dataLength+1];

  newBuffer[0] = PREFIX;
  Array.Copy(buffer, 0, newBuffer, 1, dataLength);
  buffer = newBuffer;
  dataLength++;
}


AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?

Довольно много.
Из глупостей:
1. Попытки на ходу исправить bufferLength. Зачем? Отрицательные размеры, а также размеры более длины переданного буфера не имеют физического смысла. Вместо того, чтобы пытаться их как-то скорректировать, нужно выбрасывать исключение — пусть вызывающая сторона исправляет свой код.
2. Попытки схитрить с переиспользованием существующего буфера. Зачем? Это что, оптимизация? Для оптимизации нужны результаты профайлера. Судя по остальному коду, профайлер этого никогда не мерил. Ну так и незачем заниматься усложнением на ровном месте. Выделяйте буфер всегда. Дорогая операция здесь — копирование, которое происходит в любом случае. Выделение пары сотен байт из кучи в управляемой среде ничего не стоит.
3. Повторение избыточных проверок. Это только запутывает код и мешает компилятору со средой проводить оптимизации. Проверили буфер на null один раз, в самом начале — и достаточно. Делать это в цикле тем более не имеет смысла.
4. Зачем растить столько ветвей в графе управления? DRY: достаточно ровно одной строки, которая приписывает префикс.
5. Отказ от использования встроенных средств. Array.Copy — то, что доктор прописал. Это мало того, что более понятно, так ещё и более оптимально (там внутри используется развёртка циклов и копирование как минимум по DWORD за раз). За побайтное копирование в 21 веке нужно бить логарифмической линейкой по пальцам.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re: Как не надо писать код
От: _FRED_ Черногория
Дата: 09.04.11 18:45
Оценка: 1 (1) +1 -1 :)))
Здравствуйте, AlexNek, Вы писали:

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


25 см?
Help will always be given at Hogwarts to those who ask for it.
Re: Как не надо писать код
От: Олег К.  
Дата: 09.04.11 22:45
Оценка: +1 -1 :))) :)
Зачем создал этот топик? Зайди в соседний форум по плюсам. Там в девяти топиках из десяти увидишь как не надо писать код.
Как не надо писать код
От: AlexNek  
Дата: 08.04.11 21:59
Оценка: 3 (2) -2
Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.

        public void WriteTransformation(ref byte[] buffer, ref int bufferLength, WriteByteHandler writeByteHandler)
        {
            if (writeByteHandler != null)
            {
                bufferLength = 1 + Math.Min(Math.Max(bufferLength, 0), (buffer != null) ? buffer.Length : 0);

                byte[] newBuffer;

                if (bufferLength - 1 < ((buffer != null) ? buffer.Length : 0))
                {
                    newBuffer = buffer;
                }
                else
                {
                    newBuffer = new byte[bufferLength];

                }

                for (int i = bufferLength - 1; i > 0; i--)
                {
                    if (newBuffer != null) if (buffer != null)
                            newBuffer[i] = buffer[i - 1];
                }

                if (newBuffer != null) newBuffer[0] = PREFIX;

                buffer = newBuffer;
            }
        }

Самое смешное в том, что часть строки я прочел как
bufferLength = .... Math.Max(bufferLength, 0), (buffer != null) ? buffer.Length : 0

и долго не мог врубиться как же оно работает

Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?
avalon 1.0rc3 rev 380, zlib 1.2.3

04.05.11 09:32: Перенесено модератором из '.NET' — TK
Re: Как не надо писать код
От: Powerz Россия https://zagosk.in
Дата: 11.04.11 08:46
Оценка: -2 :)
Здравствуйте, AlexNek, Вы писали:

Задача: на вход поступает int, надо вернуть последнюю цифру.
Собственно шедевр (имя метода и входного параметра изменено, все совпадения чистая случайность):

public static string GetX(int id)
{
    return id.ToString().Substring(id.ToString().Length - 1, 1);
}


Писал не какой-нибудь джуниор, а программист-архитектор-тимлид.

Переписано так:

public static int GetX(int id)
{
    return id % 10;
}
https://zagosk.in
Re[3]: Как не надо писать код
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.04.11 04:42
Оценка: +2 :)
Здравствуйте, AlexNek, Вы писали:
AN>В данном случае важнее была работоспособность.
Я не понимаю, о какой работоспособности можно говорить в коде, где кто-то присылает массив длинной 10 и просит отправить 15 байт.
Значит, автор кода забыл добавить последние 5 байт, и в устройство в результате вашей "починки" уезжает мусор. Именно такие попытки "починить на ходу" отвечают за сверхъестественно выглядящие баги, которые ищутся годами. Поверьте мне — я в детстве тоже так делал.
AN>Специальных исследований не проводил, но помнятся противоположные результаты.
Результаты вам помнятся по С++.

S>> 3. Повторение избыточных проверок. Это только запутывает код и мешает компилятору со средой проводить оптимизации. Проверили буфер на null один раз, в самом начале — и достаточно. Делать это в цикле тем более не имеет смысла.

AN>
if (newBuffer != null) if (buffer != null)

AN>Уже только эту строку можно занести в шедевры "как не надо"
Сама по себе строка ничего особенно плохого не содержит. Важен контекст.

S>> 4. Зачем растить столько ветвей в графе управления? DRY: достаточно ровно одной строки, которая приписывает префикс.

AN>С последним предложеним как то не совсем понятно
Посмотрите, сколько раз в исходном коде встречается строчка ...[0] = PREFIX.
Из-за того, что мест больше одного, нет никакой гарантии, что все ветви графа управления проходят через эту строчку. Объединяя ветви в одну и оставляя ровно одно присваивание, мы убеждаемся, что не бывает комбинации условий, когда в качестве префикса остаётся ноль.

S>> 5. Отказ от использования встроенных средств. Array.Copy — то, что доктор прописал. Это мало того, что более понятно, так ещё и более оптимально (там внутри используется развёртка циклов и копирование как минимум по DWORD за раз). За побайтное копирование в 21 веке нужно бить логарифмической линейкой по пальцам.

AN>Если предоставите линейку напрокат
Можете угрожать wireless-шнуром. Не знаю почему, но неопытные разработчики боятся его до судорог.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.04.11 03:15
Оценка: +2 :)
Здравствуйте, Sinix, Вы писали:

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


K>>Ну да — тут не всё так просто в общем случае. Например никто никогда не задумывался, почему Array.Length имеет тип int, а не uint (хотя на первый взгляд второй вариант логичнее)?


S>1. warning CS3001: Argument type 'uint' is not CLS-compliant

S>2. а собсно зачем заводить массив, который займёт >2гб памяти? (берём крайний случай — с byte[]/bool[].) В типовой системе из-за фрагментации легко получить OutOfMemory даже на 200мб.

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

А на эту тему у меня есть свежий пример из собственной практики. Увидел ворнинг о сравнении знаковых и беззнаковых в следующем коде на C++:
for (int i = vector.size() - 1; i >= 0; i--)
     foo(vector[i]);

исправил на нечто вроде
for (size_t i = vector.size() - 1; i >= 0u; i--)
     foo(vector[i]);

и потом долго не мог связать срыв крыши у программы с этим изменением.
Re[17]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 11:42
Оценка: +2
Здравствуйте, AlexNek, Вы писали:

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


AN>>>Я специально привел пример, когда этого не следует делать.

S>>Этот пример не имеет отношения к случаю проверки аргументов WriteTransformation
AN>Это вполне может быть Вашим мнением. У меня оно несколько другое.
очевидно

AN>>>Да иногда может.

S>>Иногда может что?
AN>Выдача исключения в большинстве случаев подразумевает переход на другой путь, в частности
AN>показ диалога сообщения об ошибке и аврийное прерывания текущей операции.
Вообще говоря это не так.
Но в вашем случае WriteTransformation просто продолжит нагнетать пургу. Если вашего пользователя устроит такой подход, то мне нет больше до этого дела.

S>>Вашь пользователь работает с WriteTransformation напрямую?

AN>Конечно нет, но эта функция отностися к блоку не имеющему права выдавать исключения.
Ваш блок даже не выдает код ошибки, а просто гонит. Печально то, что об этом может никто не узнать и считать что блок отрабатывает верно.

AN>>>Просто как более понятный пример

S>>Вы его неверно трактуете.
AN>Тут вопрос кто его неправильно трактует. Возможно мы его понимает по разному.
Вы его понимаете так, будто приложение должно делать то для чего оно написано, даже если данные повреждены.

S>>Если все методы приложения будут гнать пургу в ответ на пургу во входных данных, ваше приложение просто будет молча делать пургу вместо того что ожидает пользователь.

AN>никто не ведет речь о всех методах, есть просто различные части с различным "поведением".
"поведение" вашего блока — нагнетать пургу и делать вид что все ок.
Re[19]: Как не надо писать код
От: hardcase Пират http://nemerle.org
Дата: 22.04.11 13:04
Оценка: +2
Здравствуйте, AlexNek, Вы писали:

S>>Ваш блок даже не выдает код ошибки, а просто гонит. Печально то, что об этом может никто не узнать и считать что блок отрабатывает верно.

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

Запет на выброс исключений это совсем не картбланш на GI/GO (Garbage In — Garbage Out). Корректность входных данных проверять всеравно необходимо, и функция, которая не использует исключения для сигнализации, данных должна возвращать код результата (ошибки).
/* иЗвиНите зА неРовнЫй поЧерК */
Re[6]: Как не надо писать код
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 28.04.11 15:20
Оценка: 18 (1)
Здравствуйте, Sinix, Вы писали:

S>CLS — Common Language Specification, не C# Language Specification. Осложнять жизнь при портировании кода под .net — не самый лучший способ завоевать популярность.

Ну дык я про эту спеку и говорил. Массивы — это часть рантайма, а не C#

S>Нет, просто для таких задач недостаточно примитивной абстракции над непрерывным сегментом памяти. И у гипотетического SlicedArray вполне может быть Length типа long (зачем мелочиться?).

Дык уже У массивов есть LongLength

S>[k.o.]

S>Или code analysis warning, или OverflowException в рантайме при тестах, или ArgumentOutOfRange на клиенте. Всё зависит от уровня разработки.
S>[/k.o.]
Первое — возможно, второго и третьего не будет Просто код поведёт себя совсем не так, как того ожидает разработчик...
S>Но в целом да, беззнаковый тип для размерностей может породить кучу интересных проблем как раз из-за отсутствия явно недопустимых значений.
Да нет — тут проблема чисто в переполнениях и в том, что очень многие разработчики тупо не в курсе проблемы...
[КУ] оккупировала армия.
Re[10]: Как не надо писать код
От: AlexNek  
Дата: 10.04.11 20:23
Оценка: 2 (1)
Здравствуйте, xobotik, Вы писали:

x> AN>Там в параметрах функции вроде была еше длина данных. Я о том что если переделывать функцию желательно оставаться в пределах ее старых параметров.


x>
x> public void WriteTransformation(ref byte[] buffer, ref int bufferLength, WriteByteHandler writeByteHandler)
x>


x> То есть int bufferLength это длина совершенно другого какого то буфера?) То есть buffer.Length != bufferLength?

Правильнее было было бы назвать эту переменную по другому, типа "длина данных" в буфере.

x> AN>безусловно, но если бы все решали делать как они считают лучше, а не как требуется, было бы весьма напряженно. Только не сочтите это критикой или еще чем то, я AN>просто высказываю свое личное мнение.


x> Согласен, но вы же сами сказали http://rsdn.ru/forum/dotnet/4227826.1.aspx
Автор: AlexNek
Дата: 10.04.11


А что в том примере неправильно?

x> AN>Довольно просто, размер буфера в 99.999% случаях меньше длины данных. Новый буфер создается только для теоретического случая когда буфера недостаточно.


x> То есть задача состоит в следующем:

x> есть какие либо данные, есть длина этих данных, есть константа PREFIX. Данные содержаться в массиве buffer длиной bufferLength -> N, сам массив длиной buffer.Length -> M. Необходимо добавить в начало PREFIX. Если N == M || N > M, то создаем новый массив, копируем все данные в новый массив, добавляем PREFIX (и эта ситуация с вероятностью 0.001). Если N < M смещаем данные в исходном массиве buffer на одну позицию вправо и записываем PREFIX в начало. Так же необходимо вернуть новую длину данных, а это всегда N + 1.

x> Следуя из сигнатуры метода, buffer -> массив, в котором содержаться данные длины bufferLength это так ?

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

x> AN>Это по поводу статика. Если нет использования this, еще не значит что можно делать функцию статик.

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

x> Просто не понял постановки задачи=)

Типичная проблема, которую весьма трудно обнаружить

x> x>> P.S. Сообщение удалял =)


x> AN>Теперь уже поняли, появилась новая проблема работы с оффлайн бровсерами


x> Не понял)

Вы наверное еще не были в разделе "открытые проекты" и RSDN@Home? Я тоже раньше не был, но потом попробовал и весьма понравилось. Кстати, огромнейший простор для применения своих сил. Рекомендую начать ознакомление с avalon-а, а потом можно приняться и за янус. Наоборот лучше не делать, останется неприятный осадок.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[3]: Как не надо писать код
От: Sinix  
Дата: 28.04.11 02:24
Оценка: 1 (1)
Здравствуйте, koandrew, Вы писали:

K>Ну да — тут не всё так просто в общем случае. Например никто никогда не задумывался, почему Array.Length имеет тип int, а не uint (хотя на первый взгляд второй вариант логичнее)?


1. warning CS3001: Argument type 'uint' is not CLS-compliant
2. а собсно зачем заводить массив, который займёт >2гб памяти? (берём крайний случай — с byte[]/bool[].) В типовой системе из-за фрагментации легко получить OutOfMemory даже на 200мб.
Re: Как не надо писать код
От: Sinix  
Дата: 09.04.11 04:30
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

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


А CopyTo + запись префикса — слишком просто?

За ref-ы, допущение того, что bufferLength может быть меньше 0, непроверку на переполнение — приговорить к пожизненному сопровождению своего кода.
Re[3]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:25
Оценка: +1
Здравствуйте, Andrey Rubayko, Вы писали:

AR> AN>>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


AR> Неужели вы занимаетесь ревью чужого кода?

Всем иногда приходится это делать
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[6]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 10.04.11 06:37
Оценка: +1
Здравствуйте, xobotik, Вы писали:

X>Если конечно обобщенные методы не устраивают, а необходимо передавать массив byte,

X>то можно воспользоваться следующими материалами, там вроде как решаются похожие задачи с упором на производительность:
X>1) http://codelab.ru/task/cycle_shift/;
X>2) http://habrahabr.ru/blogs/algorithm/101059/;
X>3) http://devels.ru/?what=art&amp;p=486.

1ая и 3яя ссылки — ротация массивов, которая делается без использования дополнительной памяти. Для чего тут эти ссылки, если массив придется пересоздавать для добавления одного элемента? Ротация тут не нужна, ибо можно сделать копирование.
2-ая ссылка вообще о ротации битов
Re[4]: Как не надо писать код
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.04.11 14:27
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>>Если я правильно понял, то передача buffer == null и bufferLength = 0 — корректна. В этом случае нужно вернуть буфер единичного размера с префиксом.

S>Но это нифига непонятно и неожиданно. Лучше явно декларировать свои намерения — отдельным методом.
Не вижу ничего неожиданного в том, что метод трактует new byte[0] и null одинаково.
А вообще — задачи чинить архитектурные проблемы не ставилось. Может, там вообще всё надо нахрен переделать, сократив объём кода раз в пять
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 08:55
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

AN>Задача выполнена, но с ошибками. вроде пример с чтением книги приводил.

AN>Возьмер допусти OCR прогу. Не может она распознать один символ и выкидывает при этом исключение — "Стор. Не могу распознать символ". Вам это понравится

По-вашему исключения придумали что бы морочить ими голову пользователям?
Re[12]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 10:31
Оценка: -1
Здравствуйте, samius, Вы писали:

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


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


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


AN>>>>Задача выполнена, но с ошибками. вроде пример с чтением книги приводил.

AN>>>>Возьмер допусти OCR прогу. Не может она распознать один символ и выкидывает при этом исключение — "Стор. Не могу распознать символ". Вам это понравится

S>>>По-вашему исключения придумали что бы морочить ими голову пользователям?

AN>>Я только говорю, что не следует все мешать в одном корыте

S>Вот и не мешайте все в одно корыто. На примере OCR почувствуйте разницу между тем когда подали данные с нераспознаваемым символом, и тем когда подали поток данных недостаточной длины.

Так что надо вывалить исключение и сказать пшел вон?
По мне, так лучше показать пустую страницу и написать внутри что ее невозможно обработать.
Смысл в том что блок распознавания страниц должен всегда выдавать результат, а не передавать исключение наверх, те исключения просто обрабатываются "локально"
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[15]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 11:01
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

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


AN>>>Так что надо вывалить исключение и сказать пшел вон?

S>>Сначала надо уловить разницу между тем, что является корректным набором данных для метода и нет. В случае некорректного формата данных нужно кидать исключение сразу, так быстрее найдете то место, где они становятся некорректными. Вам Sinclair дал ссылку на FailFast.
AN>Я специально привел пример, когда этого не следует делать.
Этот пример не имеет отношения к случаю проверки аргументов WriteTransformation

AN>>>По мне, так лучше показать пустую страницу и написать внутри что ее невозможно обработать.

S>>Исключение разве мешает это сделать?
AN>Да иногда может.
Иногда может что?

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

S>>Кто этот смысл выдумал?
AN>Наши принципы работы с пользователем
Вашь пользователь работает с WriteTransformation напрямую?

S>>Вообще не пойму, причем тут страницы, до сих пор речь шла о WriteTransformation

AN>Просто как более понятный пример
Вы его неверно трактуете. Если все методы приложения будут гнать пургу в ответ на пургу во входных данных, ваше приложение просто будет молча делать пургу вместо того что ожидает пользователь. В лучшем случае пользователь это заметит и свяжется с вами. В худшем — кто-то пролетит на бабки.
Re[25]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 17:05
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

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


S>>Предлагаю не замалчивать проблему.

AN>Ок, кричим, что дальше?
реагируем

AN>>>Кто сказал, что такой подход используется повсеместно?

S>>Я проэкстраполировал ваше отношение к исключениям вместе с примерами распознавания. Уверен, что не ошибся.
AN>Блин, прийдется убирать модуль обработки ошибок
Занятно! Т.е. у вас есть модули которые ошибки прячут, и есть которые их спрятанные обрабатывают?
Это игра в "мафию" в одну каску

AN>Я же говорил о цепочке. Цепочка или вся работает или нет. Модуль стоящий в начале цепочки спокойно все и определяет

Он даже не может определить, ушли ли от него верные данные

AN>его задача просто ретранслировать данные если он не может этого сделать генерируются "нулевые данные"

По-моему пора завязывать.

S>>Конкретный искаженный ошибкой ответ на конкретную искаженную ошибкой команду. Вы уверены, что это то чего вы ожидаете от программы? Откуда будет уверенность что получили ответ на то что посылали вообще?>

AN>То есть две ошибки сразу?
AN>Команда не может исказится в данном методе. По крайней мере, я не вижу этого.
Вы исходите из того что весь код написан верно. Это работает только в том случае, если весь код написан верно. Если что-то неверно, то ошибка размазывается по всей цепочке, т.е. никаких данных о том, на каком этапе возникла ошибка у вас нет. Есть только "нулевые" данные на выходе.
В общем, успехов в отладке!
Re[39]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.04.11 18:02
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

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


s>> То что она не предоставляет гибкость

AN>Тогда это будет уже совсем другая система, даже точнее не система а монстрик
AN>- она должна иметь множество путей обработки ошибок
AN>- она должна различать определенные ошибки и выбирать требуемый путь.
AN>- она должна знать что конкретно делать при каждом пути.
AN>- она должна располагаться на многих уровнях и иметь доступ к данным ее не касающихся.
Не знаю, что у вас за особенная система, но все перечисленное (кроме доступа к не касающимся данным) можно обеспечить грамотным использованием try/catch конструкций и глобальными обработчиками.

s>> s>> Дык у вас и то и другое ничем не отличается от нормы


s>> AN>откуда такая уверенность?


s>> из вашего кода

AN>Во первых, код не мой, а во вторых это всего лишь маленькая часть.
Вижу, по выделенному возражений нет, кроме вопроса принадлежности кода?

s>> AN>что возвращаемое значение не является кодом возврата


s>> Там такого не написано

AN>В противном случае там бы стояло, в случае ошибки.....
AN>И сравните описание возврата:
AN>-здесь
AN>-здесь
Походу вы собираетесь и дальше препираться на тему можно ли трактовать результат TryGetValue кодом возврата, вместо того что бы согласиться что TryGetValue позволяет разобраться как с корректностью аргумента, так и с наличием записи?
Давайте назовем результат TryGetValue вместо кода возврата признаком успеха. Это изменит суть претензий?

s>> И что будете делать при обнаружении бага или изменении требований? Считать вероятность или исправлять?

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

s>> Пусть не всегда. Но веские причины все-же не названы. Отсылка к OCR здесь ложная, т.к. ситуация другая.

AN>Как раз именно абсолютно такая же, считайте что данная часть модуля подает команды на сканирование документа.
Битая команда и нераспознаный в корректных данных символ — это весьма далекие ситуации.

s>> AN>А отчего микрософт не рекомендует его ловить, а делает так?


s>> Вопрос с подвохом. Покажите мне для начала то место где микрософт не рекомендует ловить исключения WriteLine.

AN>Подобные вещи обычно находятся в коде, на такие мелочи они не размениваются.
Т.е. микрософту вы приписали тезисы вашей фантазии, разыгравшейся на почве примеров MSDN?

s>> Как считаете, для чего дан перечень исключений методов WriteLine, разве для того что бы их не ловили?

AN>Ок давайте будем ловить. Понравилось?

AN>
AN>

Я чувствую что этим безграмотным примером вы хотели ввести меня в какие-то противоречия, а не показать свое умение работы с исключениями. Потому комментировать его не буду. Но так же вижу, что у вас нет ответа на вопрос, зачем перечень исключений WriteLine представлен в MSDN...

s>> Показать вам код, который вышибет исключение из процитированного примера ровно в строчке WriteLine?

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

Вернемся к посылу

Давайте попросим код ошибки от Console.WriteLine и будем извещать пользователя если что не так

Механизм исключений для того и предназначен, что бы извещать пользователя, разработчика, или еще кого. Но делает это он именно на том уровне, где стоят обработчики. Тыкать обработчики на каждый вызов — не очень умно. Только не говорите что в примерах MSDN на try/catch делается именно так Все примеры MSDN рассчитаны на объем кода в две ладошки и не подразумевают продвинутых подходов к обработке исключений.
Re[41]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.04.11 20:01
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

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


s>> Походу вы собираетесь и дальше препираться на тему можно ли трактовать результат TryGetValue кодом возврата, вместо того что бы согласиться что TryGetValue позволяет разобраться как с корректностью аргумента, так и с наличием записи?

AN>Про корректность аргументов там ничего не сказано.
см. секцию исключений

s>> Битая команда и нераспознаный в корректных данных символ — это весьма далекие ситуации.

AN>Из-за этой команды головка хреново синхронизировалась со сканером и символ/строку уже не распознать, их может просто не быть там.
Во! Из-за битой команды может пострадать результат сканирования, потому ситуации с битыми командами надо как минимум протоколировать и разбираться с ними, что бы максимально исключить возможность порчи данных команды.
Однако ситуация с нераспознаванием символа/строки может случиться и с валидной командой для головки, например из-за дефекта носителя. Это вообще норма, с этим ничего сделать нельзя, в этом софт не виноват и крайних искать не надо, так же как и исправлять что-либо. Т.е. одно может быть следствием другого, но не признаком другого.

s>> s>> Как считаете, для чего дан перечень исключений методов WriteLine, разве для того что бы их не ловили?

AN>вопрос в том что это даст практически?
Практически это дает контроль над исключениями, возникшими внутри WriteLine. Т.е. программист имеет возможность обрабатывать их согласно постановке задачи. Обычно это не требуется, но если взять тот же пример, когда работа не должна убиваться при ошибке вывода в консоль (IO или FormatException), программист может обработать эту ситуацию. В другом случае он не будет спеицальным образом обрабатывать эти исключения и получит FailFast, который позволит увидеть проблему на раннем этапе.

AN>Вообще то в консольной программе мессаже бох не должен вообще появляться.

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

s>> AN>И что даст это исключение для пользователя, в данном случае?


s>> Открою секрет, что ловля исключений подразумевает не только показ MessageBox-а пользователю. В частности, например, гашение исключения позволит коду работать дальше, невзирая на случившиеся проблемы.

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

s>> Проброс его наверх предоставит выбор вызывающему коду, обертывание позволит классифицировать исключение специальным образом.

AN>Ну это если возможны варианты. А если есть всегда в данной части кода только вариант
AN>с "гашением"?
Хотя бы сбросить в лог для дальнейшего разбора полетов.
s>> В любом случае, если код данного уровня не предполагает о том, как должно быть обработано исключение, он и не должен его перехватывать и уж тем более показывать пользователю MessageBox.
AN>Так что же нужно делать по этому исключению?
AN>вот именно это и хотелось бы узнать.
Выяснять и устранять причины битых данных. Если причин нет, то исключение не помеха, а страж.

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

AN>А есть вариант "глобального гашения"?
Любое глобальное решение не подразумевает продолжение работы с места возбуждения без оборачивания кода в try/catch.

AN>Понимаете, я не явлюсь противником использования исключений, а только хочу сказать, что их использование не подразумевает 100% покрытие. Нам нужна какая либо реакция на ошибку и не всегда нужно кричать об ошибке.

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

AN>Ну типа выезжаю я на перекресток по главной улице и вижу машину которая также думает, что едет по главной. Да можно и посигналить и дождаться стражей порядка после аварии, но можно и просто притормозить. Конечно, в этом случае никто не узнает о нарушении. Но вопрос в том, что будет лучше в определенных ситуациях: кричать о нарушении или промолчать?

Не корректное сравнение. Обсуждаемая потенциальная ошибка с рассогласованием данных команды будет аналогична ситуации, когда вы выезжаете на перекресток, а реакцией на нажатие на тормоз будет эффектное открытие багажника. Если после вы захотите разобраться, отчего такой глюк произошел, у вас должна быть хоть какая-то информация. Я не настаиваю что это должна быть ажурная надпись на airbag-е, выскочившая в процессе экстренного маневрирования (аналог MessageBox-а). Но хоть что-то, с чем сервисмен разберется, подключив диагностическую колодку.
Re[4]: Как не надо писать код
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 28.04.11 14:29
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>1. warning CS3001: Argument type 'uint' is not CLS-compliant

Ну это вообще говоря не проблема для авторов спецификации

S>2. а собсно зачем заводить массив, который займёт >2гб памяти? (берём крайний случай — с byte[]/bool[].) В типовой системе из-за фрагментации легко получить OutOfMemory даже на 200мб.

Ага, "640кб хватит всем". Проходили уже

Но есть ещё одна причина. Смотри сюда:

static class Program
    {
        static void Main(string[] args)
        {
            DoSomething(new byte[0]);
        }
        static void DoSomething(byte[] arr)
        {
            for(var i = 0; i <= arr.Length() - 1; i++)
            {
                
            }
        }

        private static uint Length(this Array arr)
        {
            return (uint) arr.Length;
        }
    }

Как ты думаешь, что будет, если выполнить этот код?
[КУ] оккупировала армия.
Re[8]: Как не надо писать код
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 28.04.11 16:04
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Оно есть начиная с .NET 1.1. Позор на мою неседую голову, что ещё сказать.



S>Кстати да, i у нас будет int. И в цикле нет доступа к массиву. А вот почему не будет overflow при checked-билде?

Тока что проверил — таки ты прав — будет переполнение. Но что-то я ни разу не видел таких билдов в живой природе

S>И не только в них. Если результат IndexOf() == uint.MaxValue — это значит что мы ничего не нашли, или что нашли последний элемент? Конечно можно отдавать Nullable<uint>, но, чую, это только самое начало проблем от использования uint для индексирования массивов/списков.

Тут тут тока nullable, ну или вообще экепшен бросать
[КУ] оккупировала армия.
Re[61]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.04.11 18:55
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

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


AN>я немного подчистил текст, если что лишнее убрал — не специально.

нет проблем

s>> По поводу консоли — можно согласиться. А GetServices с чего стал глобальным?

AN>А сколько у вас имплементаций для "хранилища" сервисов?
Обычно не больше одной

AN>Кроме того он может выглядеть и так

AN>ServiceController.GetServices();
У тех кто не видел проблем от глобальных состояний — может.

s>> AN>Должно быть нечто видное "везде".


s>> Для чего, и собственно что именно?

AN>Что именно абсолютно не интересует (вполне возможно, что подобная формулировка режет слух но это просто различие в уровнях абстракций)
Под что именно я пытался уточнить, речь о глобальных состояниях только, или вообще о методах, классах?
AN>А для чего? Есть задача иметь доступ к чему то из любой части программы.
AN>Ну типа Trace.WriteLine();
Хоть оно и из коробки, но это далеко не образец для подражания. Если при активном использовании Trace начать манипулировать TraceListener-ами во время выполнения в многопоточном приложении — будет большая каша, например.

s>> В исходной задаче вы сказали что "можно определить корректность аргументов". И это подразумевает некоторый способ, который не изменится при смене реализации абстракции.

AN>Нет, это никак не подразумевает конкретный способ. Я даже не знаю какие будут аргументы и как их необходимо проверять. Я только знаю что должна быть проверка и что она возвратит результат опять таки в каком либо виде.
AN>То есть должно быть нечно которому "я дам" аргументы и "могу спросить" ответь ка это верно или нет?
Например, у TryGetValue указано, что должен вылетать ArgumentNullException. Это значит что у всех реализаций должно быть так. Пусть на некотором уровне абстракции способ не важен, но мы не сможем ввести абстракцию, не указав конкретный способ для получения информации о корректости аргументов. Конкретный способ тоже может быть абстрактным, но у этой абстракции должен будет быть конкретный интерфейс.

s>> Нет варианта без исключений. Есть вариант без обработки исключений. Потому как нет такой WriteLine, которая бы не кидала исключений вообще никогда.

AN>Держите

AN>
WriteLine()
AN>{
AN>}
AN>

StackOverflowException вряд ли имеет смысл обрабатывать, но то что он оттуда вылетит при определенных обстоятельствах — это факт.

s>> Т.е. если командный, то будете склонны изобретать свой метод, вместо использования общеизвестного? Не ясна логика.

AN>Я всего лишь сказал, что метод работы будет влиять на выбор, но ничего не говорил о конкретном выборе. Хотя и метод работы не единственное, что будет влиять на выбор. Если допустим, я делаю прогу один, для себя лично, то у меня нет никаких дополнительных ограничивающих факторов, но по мере отклонения от этой линии факторов становится все больше и они могут изменять свой вес.
А я всего лишь хотел спросить, влияет ли командная разработка в пользу своих решений вместо традиционных, не известных команде?

s>> варианты не интересны. Есть что-то неочевидное для соседа. Будет ли алгоритм Дейкстры менее понятен для соседа, чем ваш велосипед?

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

s>> А потом еще 2 дня объяснять команде, чего тут понаписано?

AN>А другом случае пусть они сами потратят неделю на понимание, алгоритм то не мой, отчего его объяснять. Сами должны знать...
Ваш можно объяснить за 2 дня, а не ваш пусть неделю понимают? Конечно, все пишут такие тупые и непонятные вещи, как Math.Max
AN>Вообще то из практики: требуется хотя бы полгода работы, для объяснения принципов аж в течении двух дней.
AN>

Это смотря кому объяснять

s>> Поясните, будьте добры. Вы его упомянули в ответ на мое предложение подтянуть команду.

AN>Ну, можно далеко не ходить за примером "выпендривания"
AN>
bufferLength = Math.Max(bufferLength, 0)
AN>

AN>Изучать нового вроде ничего и нужно, но и понять с первого взгляда, "просмотром кода" не получится.
Что тут не понять с первого взгляда? И как написать так, что бы можно было понять с первого взгляда?

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

Возможно для такого чуда есть повод?

AN>Вы же имели видимо в виду видимо "неизвестное использование"

AN>Ну типа
AN>
return await ххх

Что за неизвестное использование? Спрашиваем гугль и оно становится известное. А вообще в блогах об этом с пол года пишут.

AN>А вот при чем здесь инструменты до меня не дошло.

Притом что компилятор, Math.Max, алгоритм Дейкстры, await, исключения и абстракции над WriteLine — это инструменты для решения задач. Мне показалось, что вы принебрегаете одними, довольно простыми, по причинам "сложности", но используете гораздо более сложные...

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

AN>Что то я не припоминаю где это я мог упоминать.

s> Если манипулирование абстракциями на таком уровне является проблемой для команды, то ну ее нафик, эту абстракцию.
Дело не в конкретной проблеме, а в общем подходе. И дело, в основном, упирается во время.
s> А может стоит подтянуть команду? Все же это не ахти какой уровень владения программированием.
Сегодня она одна, завтра совсем другая. Главный принцип "не выпендриваться".


s>> но гипертрофированный свитч, по всей видимости, не является проблемой для понимания его работы?

AN>Так а что там нужно понимать? Есть выбор и дохрена "комнат".
AN>Нужно что новое — добавляешь "комнату" и все.
Вот опять, Math.Max непонятно, а 10и-страничный свитч — "что там нужно понимать?"

AN>Можно было допустим "выпендрится" с атрибутами и забить "комнатки" в функции.

AN>Тогда также было бы просто добавить "комнату", но зато общий код получился бы неочевидным, нужно было уже "думать" как, почему и зачем.
Мне, например, проще думать чем читать 10 страниц со свитчем или улавливать какие-то закономерности на 10и страницах.
Re[67]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 30.04.11 20:32
Оценка: +1
Здравствуйте, AlexNek, Вы писали:

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


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


s>> s>> Реализацию считать глобальной, потому что нет других реализаций? Вот допустим что существует лишь одна реализация IList<T> — List<T>. Можно ли ее считать глобальной?


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


s>> Обычно под реализацией/имплементацией подразумевают типы, а не экземпляры.

AN>Тогда скажите как перевести например Data Type Implementation?
Реализация типов данных
AN>Вы видимо имеете в виду Interface Implementation?
Нет, я не понимаю, причем глобальность и число реализаций?

s>> Доступность типа в дотнете определяется не количеством, а модификатороми видимости для него и типов, в которые он вложен. Т.е. непонятно что вы подразумеваете под применением термина глобальность к типу(реализации/имплементации).

AN>Он подразумевается не к типу.
А к чему?

s>> Все зкземпляры глобальны в рамках процесса. Т.е. имея его ардес/ссылку на экземпляр, не составит труда обратиться к нему отовсюду.

AN>И откуда нам знать этот адрес или ссылку? И кстати, где то об этой глобальности и идет речь.
Обычно передается по стеку. Но можно сохранить в глобальной переменной.
AN>Как например обратится к A1, A2?
AN>
void f()
AN>{
AN>  int A1=0;
AN>}
AN>

Передайте адрес A1 тому, кто будет к переменной обращаться.
AN>
public class X
AN>{
AN>   public int A2 = 0;
AN>}
AN>

аналогично.

s>> s>> Вы же сказали что это будет "глобальная переменная". А это global state, как не реализуй.


s>> AN>Можно списать на "ошибки" вербальной коммуникации, я подразумевал под этим несколько другое.


s>> И все-таки непонятно, что именно.

AN>Могу привести некоторые примеры глобального: static и singleton
AN>Console.WriteLine();
AN>A.VariableX;
AN>A.GetInstance();
Дык это global state, или убедите меня в обратном.

s>> s>> Так вот, использование глобального хранилища сервисов вряд ли чем-то лучше, чем использование глобальной переменной для каждого сервиса.


s>> Может ссылку дадите?

AN>Не имею понятия на что именно.
На то, что вы подразумеваете под "глобальным"

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

Пардон, перепутал с каким-то другим форумом. Здесь можно.

AN>Тогда как узнать в каком ключе нужно говорить с человеком? Можно конечно действовать методом проб и ошибок, а можно и просто каким то образом спросить.

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

s>> У нас еще разница в терминологии

AN>Я это тоже заметил Просто мы находимся в различных средах.
Уверен, что многие термины, которые я использую, сообщество rsdn в среднем воспринимает схожим образом. Если что-то я не стесняюсь уточнять значения. Например, на википедии (но не на русской).

s>> Это фактически и есть интерфейс метода, выполняющего эмуляцию частичного применения функции. Реализация функции занимает одну строчку, делает она вещи, которые не зависят от A, B и тем более C.

AN>Ну это если придерживаться точки зрения что List<T> не зависит от T.
А есть другая точнка зрения?
AN>А если он от него не зависит, то его вполне можно убрать, но убрать то мы его не можем, значит какая то зависимость все же есть?
T — это тип generic параметра. От типа параметра свойства List<T> не зависят и это верно. Вы же тут говорите не о зависимости от типа T, а о зависимости от наличия generic параметра. Т.е. как-бы перескочили на другую зависимость. Это как если я перейду на зависимость List<T> от "i". Если ее убрать, будет Lst<T>, значит зависимость от "i" имеется
s>> Этот милый прием позволил мне не писать порядка двухсот классов в текущем проекте.
AN>Мне пока сложно представить такую экономию, но я бы предпочел чего попроще, может с не такой большой экономией.
Ваше право, но мне сложно представить что-то проще.

s>> Да, специфично.

AN>каким образом? Только из-за того что попало "под горячую руку".
Тем образом, что ThreadAbort может выскакивать практически откуда угодно.
s>> Нет, не упомянуто.
s>> В "однопотоковом" оно тоже может вылететь.
AN>Вот так, просто само по себе?. И что будет являться инициатором?
Что-нибудь, что решит кончить ваш поток. Но если вы хорошо погуглите, то увидите кучу случаев, когда оно вылетает во вполне невинных сценариях, например
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("http://someurl.com/");
HttpWebResponse resp = req.GetResponse();


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

AN>Про это вроде разговора не было.
Не было, но вы спросили, обсуждаем ли мы работу "многопотоковых приложений". А я отвечаю, что в дотнете таковым является практически любое приложение (наверняка любое).

s>> Предложите другой вариант, кроме как забивание на факт существования исключений. Напомню, что WriteLine взята лишь для примера, и вместо нее может быть любая другая функция. Мы говорим о концепте, не так ли?

AN>Да, о двух разных подходах.
Т.е. варианта, кроме забивания на исключения, не будет?

s>> я не понял, т.е. если бы там стояло 100 вместо 0-я, то ничего бы не смущало?

AN>Не смущало, если бы там стояло bufferLength2.
var bufferLength2 = 0;
bufferLength = Math.Max(bufferLength, bufferLength2); // ниужели так бы не смущало?


s>> (if, x<0, y=10) — тоже можно прочитать на разговорном языке, только здесь два небольших отличия, меняющих смысл кардинально. Но что самое интересное, (max, x, 0) — тоже легко читается.

AN>И что будет понятно немедленно после прочтения, а также и во время?
AN>"Найдем максимум из двух чисел: Х и 0"
Да, а что тут надо еще понять?
AN>Сравните
AN>"Если Х меньше нуля то сделать его равным нулю" — не нужно ничего не думать ни пояснять, уже во время чтения мы получаем четкие команды.
Вы разве сами не понимаете разницы? В одном случае описано некоторое свойство результата. В другом — команды к получению результата. Для того что бы понять, что будет в результате, вы предпочитаете вместо описания результата описание команд к его получению. Давайте усложним задачу и перейдем от объявления max к объявлению qsort/sin/bind. Вам все еще будут понятнее наборы инструкций по достижению результата?

s>> Давайте теперь прикинием, что же нам больше знеакомо, max или if по жизни? Пример: нужно взять самое большое/красное яблоко из 5и штук, отбросив всякую скромность и деликатность.

AN>Заметьте: Выбираем из пяти одинаковых предметов одно.
Кто сказал что из одинаковых?

AN>Теперь проделайте с детьми следующий эксперимент:

AN>уберите все яблоки со стола и скажите принести самое большое яблоко со стола, имея в виду яблоко нарисованное на скатерти. Будем делать ставки сколько человек принесет скатерть и через какое время?
Не понял, куда вас унесло в поисках аналогии.

s>> Любой ребенок выберет его бессознательно, не сравнивая при этом каждое с каждым и не оперируя if-ами. А к if-ам вы привыкли, видимо уже в разговоре с компьютером. И так хорошо привыкли, что более высокий уровень общения с компьютером у вас вызывает дискомфорт.

AN>Дело не только в привычке. Вот вы пришли в кино зал, что вы там ожидаете увидеть?
кресла, экран, кино, людей. Но я не понимаю к чему вопрос. Когда вы передаете в max два числа, что вы ожидаете от этих чисел, почему нельзя в max подать длину буфера и 0? Там же не сравниваются вес со скоростью, в конце концов
s>> Заменяете ли вы if-ами виртуальные вызовы? Если нет, то что вы слышали о виртуальных вызовах до знакомства с программированием?
AN>Не понятно к чему вы клоните.
Я клоню к повышению абстракции. Работа программиста связана со множеством вещей, которые не знают не знакомые с программированием. Отказываетесь ли вы от этих вещей в пользу вещей, знакомых не знакомым с программированием?

s>> Ну и не будете же вы для каждого if-а плодить GetSomething(x)? Мне тут лично max кажется более уместным, т.к. что делает max мы можем догадаться, а что подразумевается под NormalizedBufferLength — тут нужны экстрасенсы.

AN>Ну вот примерчик, какого либо выражения.
AN>x = Max(Max(acd,0) + 2, Min(GetX() + wsa * 3 / 8, GetAbc(1,2,3,4,5)))
AN>И возможной записи
AN>x = Max(GetWeight1(),GetWeight2())
AN>Не знаю как вам, но мне больше по душе второе.
Вы утрируете. Возможность использования в качестве выражения не подразумевает само по себе необходимость использования только такого варианта. У if-а такой возможности (в C#) нет. И это определенно недостаток.
Вот мой пример:
var maximum = max(a, max(b, max(c, d)));

свой с if-ами можете не приводить.

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

AN>Не нужно догадываться, можно глянуть описание или код при необходимости. Я просто сразу вижу — происходит что то с размером, он каким либо образом меняется. Обычно на первом этапе просмотра этого достаточно.
Ниужели это будет понятнее чем max(buffLength, 0)?

s>> Мне встречалось.

AN>Именно в качестве преобладающего использования или просто попадалось?
Достаточно часто встречался с тем, что автор идеи не был в состоянии ее доступно объяснить.

s>> Вы не пытались объяснить смысл алгоритма Дейкстры (например) программисту, совершенно незнакомому с теорией графов?

AN>Т.е этот случай должен быть неинтересен, так как "Они друг дружке что-то принципиально новое вряд ли объяснят."
А что тут принципиально нового? пол века минуло алгоритму.

s>> ну фиг с ним с await. Некоторые до сих пор находят для себя yield return. Значит ли это что его нельзя использовать сразу в проекте? И у вас что, есть перечень конструкций, которые можно/нельзя использовать в проекте?

AN>Да есть, и довольно обширный (как раз все что не попало в стандарт 2.0). Изменить довольно затруднительно, по различным причинам.
Надеюсь, что причины тому разумные.

s>> У меня есть обратный пример, когда проект был скован .net 2.0 спустя пару лет после выхода 3.5. Когда я протащил в проект linq (сваял аналог linqbridge), команда сначала отнеслась без этнузиазма, но спустя пару недель начали продуктивно применять.

AN>Вполне могу это понять, но для этого нужно вначале убедить большинство команды в ее полезности и изменить правила. Иначе получится полный бардак, я хочу добавить А, другой Б, третий С и так каждый месяц.
Хочу — это не то что движет программистами. Обычно ими движет "не хочу": Не хочу делать эту хрень, когда ее можно не делать при схожем результате.

s>> А я 8 лет проработал в конторе, где его до сих пор предпочитают другим способам переходов.

AN>Ну если бы я занимался исключительно программированием железа, то вероятно был бы в похожей ситуации. "Железки" я просто не считаю (там играют по другим законам). Видимо более правильно было бы ограничить неиспользование гото определенной средой "моего обитания" в фирме.
Фирма железа не кует, просто в период пика интереса к программированию ведущих специалистов был популярен Фортран.

s>> s>> Думать можно разными путями, а уж недумая —


s>> AN>Это довольно просто.

s>> AN>Предположим, я или скажу
s>> AN>"В темной темнице красны девицы.
s>> AN>Без нитки, без спицы вяжут вязеницы"
s>> AN>или просто покажу картинку.
s>> AN>Что быстрее доведет до цели, о чем это я?

s>>

AN>Получается даже немного думая тяжело сразу понять ответ, а вот картинка
AN>
AN>Так что быстрее? Думать или не думать
Быстрее думать. Но вы изволите хитрить, т.к. сравниваете алегорическое описание с визуальным образом, вместо того что бы сравнивать декларативное описание с императивным.

AN>Никогда раньше не пользовался онлайн клиентами, но оказалось удобнейшей штукой.

Пытался раза 3. Не судьба.

s>> AN>
s>> AN>  methodInfo.Invoke(target, null);
s>> AN>


s>> На сколько я понимаю в этих корках от апельсинов — проблема вовсе не в выпендреже, а в вызове через MethodInfo.Invoke. Если создать Action из methodInfo, а потом вызвать его, то будет и стек и StepInto, и девченки.

AN>А каким образом "убрать" Invoke или если я запускаю Thread в одном месте, а он вызывает функцию из другого места?
Какого другого места? Причем тут Thread?
Вы не путаете случаем MethodInfo.Invoke с Control.Invoke?
Re[8]: Как не надо писать код
От: Andy77 Ниоткуда  
Дата: 11.05.11 05:26
Оценка: +1
Здравствуйте, Sinix, Вы писали:

S>Так способов куча — BigArray, MMF, аллокация в нативной куче... Всё не подходит?


Подходит, но без костылей было бы лучше.
Re: Как не надо писать код
От: AlexNek  
Дата: 08.04.11 22:10
Оценка:
Здравствуйте, AlexNek, Вы писали:

foreach (var group in hash
        .GroupBy(rq => rq.IsRead)
        .Select(grp => new { IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds) }))
    MarkMsgsRead(
        _provider,
        group.Ids,
        group.IsRead);


Незнаю как вы, но большой одной строки для foreach я как то слабо представляю, поэтому также не смог сразу врубиться, не говоря уж об обилии лямбд
avalon 1.0rc3 rev 380, zlib 1.2.3
Re: Как не надо писать код
От: xobotik Россия  
Дата: 09.04.11 03:47
Оценка:
Здравствуйте, AlexNek, Вы писали:
if (buffer != null)

Порадовало такое ощущение что код писал параноик)

Да и на фига массив по ссылке передавать?)))

А можно ли постановку задачи, чтобы выложить свою версию метода?
С уважением!
Re: Как не надо писать код
От: Andrey Rubayko  
Дата: 09.04.11 06:22
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.
Re[2]: Как не надо писать код
От: Andrey Rubayko  
Дата: 09.04.11 06:27
Оценка:
AN>>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.

Мде. Поспешил запостить.

Неужели вы занимаетесь ревью чужого кода?

В целом написано, конечно, топорно. Человек не знал что есть такая штука как "??", но код будет работать. Единственное, что умиляет — newBuffer = buffer. Вот тут как раз надо человека засадить за изучение описания C# из MSDN и конкретно книгу Джеффри Рихтера.
Re[2]: Как не надо писать код
От: Andrey Rubayko  
Дата: 09.04.11 06:33
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


AN>
foreach (var group in hash
AN>        .GroupBy(rq => rq.IsRead)
AN>        .Select(grp => new { IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds) }))
AN>    MarkMsgsRead(
AN>        _provider,
AN>        group.Ids,
AN>        group.IsRead);


AN>Незнаю как вы, но большой одной строки для foreach я как то слабо представляю, поэтому также не смог сразу врубиться, не говоря уж об обилии лямбд


Вот тут как раз надо смотреть как работает механика на лямбда. Иначе у меня такое подозрение, что запрос энтот будет выполнятся на каждой итерации цикла. Возможно даже цикл получится бесконечным. Ну и помаркать сообщения можно бы было напрямую лямбда-запросом. Но это уже всякие извращения.
Re[2]: Как не надо писать код
От: User239 Россия  
Дата: 09.04.11 06:52
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


AN>
foreach (var group in hash
AN>        .GroupBy(rq => rq.IsRead)
AN>        .Select(grp => new { IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds) }))
AN>    MarkMsgsRead(
AN>        _provider,
AN>        group.Ids,
AN>        group.IsRead);


AN>Незнаю как вы, но большой одной строки для foreach я как то слабо представляю, поэтому также не смог сразу врубиться, не говоря уж об обилии лямбд


По-моему как раз наоборот простой читаемый код
Конечно можно было бы написать
void FindAndMarkMsgs(bool isRead)
{
   MarkMsgsRead(_provider, hash.Where(rq => rq.IsRead == isRead).Select(rq => rq.Id), isRead);  
}

FindAndMarkMsgs(true);
FindAndMarkMsgs(false);


Возможно выглядит проще. Но при изменении типа IsRead, к примеру было bool, стало bool?, придётся добавить вызов FindAndMarkMsgs(null). В варианте же с группировками ничего менять не надо.
Re: Как не надо писать код
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 09.04.11 07:09
Оценка:
Здравствуйте, AlexNek, Вы писали:

Вчера наткнулся на следующий код разбора аргументов командной строки (код упрощен, но сам цикл и разбор аргументов сохранен):

static void ParseCommandLineArgs(params string[] args)
{
    string param1 = "undefined";
    string param2 = "undefined";
    int i = 0;
    while(i < args.Length)
    {
        if (args[i] == "param1" && args.Length > ++i)
        {
            param1 = args[i++];
        }
        else if (args[i] == "param2" && args.Length > ++i)
        {
            param2 = args[i++];
        }
    }
    Console.WriteLine("param1 = {0}, param2 = {1}", param1, param2);
}
void Main()
{
    // Выведет: param1 = value1, param2 = value2
    ParseCommandLineArgs("param1", "value1", "param2", "value2");
    // А здесь: param1 = value1, param2 = undefined
    ParseCommandLineArgs("param1", "value1", "param2");

}


С кодом все нормально, но чтобы понять, нет ли ошибки на единицу нужно каждый раз напрягаться.
Re[3]: Как не надо писать код
От: _FRED_ Черногория
Дата: 09.04.11 07:15
Оценка:
Здравствуйте, Andrey Rubayko, Вы писали:

AR>…Человек не знал что есть такая штука как "??", но код будет работать.


А где бы вы применили этот оператор в показанном коде?

AR>Единственное, что умиляет — newBuffer = buffer. Вот тут как раз надо человека засадить за изучение описания C# из MSDN и конкретно книгу Джеффри Рихтера.


А не расскажете поподробнее?
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Как не надо писать код
От: Andrey Rubayko  
Дата: 09.04.11 07:39
Оценка:
Здравствуйте, _FRED_, Вы писали:

_FR>Здравствуйте, Andrey Rubayko, Вы писали:


AR>>…Человек не знал что есть такая штука как "??", но код будет работать.


_FR>А где бы вы применили этот оператор в показанном коде?


Ааа. Недосмотрел.

Там таки длину присваиваем

Просто давече видел другой код:


(buffer != null) ? buffer : 0


Вот и подумал что тоже самое.

AR>>Единственное, что умиляет — newBuffer = buffer. Вот тут как раз надо человека засадить за изучение описания C# из MSDN и конкретно книгу Джеффри Рихтера.


_FR>А не расскажете поподробнее?


Ну как. В данном случае просто копируется указатель на массив buffer в newBuffer. Честно говоря, мож так и надо и мы не будем использовать начальное значение переменной buffer. Так что ладно.
Re: Как не надо писать код
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 09.04.11 08:26
Оценка:
Здравствуйте, AlexNek, Вы писали:

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

[skiped]

AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


Более того, я осмелился этот код переписать. Вот что у меня вышло:

public byte[] WriteTransformation(byte[] buffer, int bufferLength)
{
    // Выделяем проверку предусловий в отдельный блок, что на порядок упрощает весь остальной код.
    // Контракты просто упрощают запись, но никто не мешает проверить предусловия руками.
    Contract.Requires(buffer != null);
    Contract.Requires(bufferLength >= 0);
    Contract.Ensures(Contract.Result<byte[]>() != null);

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

    // А теперь демонстрируем уличную магию того, как проверка предусловий упрощает код:
    // Было: bufferLength = 1 + Math.Min(Math.Max(bufferLength, 0), (buffer != null) ? buffer.Length : 0);
    // Меняем: (buffer != null) ? buffer.Length : 0 --> buffer.Length, благодаря buffer != null
    // Меняем: Math.Max(bufferLength, 0) --> bufferLength, благодаря bufferLength >= 0
    // Добавляем комментарий и вот, что мы получаем в итоге:
            
    // Необходимость +1 обусловлена тем, что в нулевой байт выходного буфера мы поместим PREFIX
    bufferLength = 1 + Math.Min(bufferLength, buffer.Length);

    byte[] newBuffer;

    // Теперь меняем следующий код:
    // Было: if (bufferLength - 1 < ((buffer != null) ? buffer.Length : 0))
    // Проверка buffer != null, уже не нужна
    // Получаем: if (buffer.Length > bufferLength - 1)
    // Заменяем > на >=:
    // if (buffer.Lengh >= bufferLength)
    // Инвертируем логику, поскольку она проще
    // Результат: if (buffer.Lenfth < bufferLenfth) ...
    // Добавляем комментарий и вот, что получаем в результате:

    // Нам нужно удостовериться, что в исходном массиве есть место под дополнительный
    // байт префикса:
    if (buffer.Length < bufferLength )
    {
        newBuffer = new byte[bufferLength];
    }
    else
    {
        newBuffer = buffer;
    }

    // Все, что удалось улучшить в этом коде, так это избавиться от лишних
    // проверок и добавить комментарий, поясняющий причину перебора элементов
    // "справа". Кстати, Array.CopyTo здесь не подойдет, поскольку он копирует
    // *все* элементы массива, а реальный размер массива buffer может быть большим

    // Добавляем комментарий:
    // Теперь нам нужно скопировать все элементы из массива buffer в newBuffer, сместив
    // каждый из них на  один индекс вправо, чтобы в нулевой индекс поместить PREFIX
    for (int i = bufferLength - 1; i > 0; i--)
    {
        newBuffer[i] = buffer[i - 1];
    }

    // Здесь тоже проверка уже не нужна
    newBuffer[0] = PREFIX;

    // У нас все еще есть проблема, поскольку в некоторых случаях мы меняем переданный буфер,
    // так что, если размер этого массива обычно небольшой, то я бы предпочел, чтобы всегда
    // возвращался новый объект.
    // Неизменяемость (или имутабельность) - это отличная техника программирования!
    return newBuffer;
}
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:06
Оценка:
Здравствуйте, SergeyT., Вы писали:

ST> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


ST> [skiped]


ST> AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


ST> Более того, я осмелился этот код переписать. Вот что у меня вышло:


А для NET 2.0 это тоже будет работать?
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:06
Оценка:
Здравствуйте, SergeyT., Вы писали:

ST> Вчера наткнулся на следующий код разбора аргументов командной строки (код упрощен, но сам цикл и разбор аргументов сохранен):


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


Чтобы понять как работает также нужно напрягаться.
Называется "экономия строк"
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[3]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:06
Оценка:
Здравствуйте, User239, Вы писали:

U> AN>
foreach (var group in hash

U> AN>        .GroupBy(rq => rq.IsRead)
U> AN>        .Select(grp => new { IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds) }))

U> AN>    MarkMsgsRead(
U> AN>        _provider,
U> AN>        group.Ids,
U> AN>        group.IsRead);


U> AN>Незнаю как вы, но большой одной строки для foreach я как то слабо представляю, поэтому также не смог сразу врубиться, не говоря уж об обилии лямбд


U> По-моему как раз наоборот простой читаемый код

Может дело привычки, но первое что я увидел, было
foreach (var group in hash

Затем уже начинаешь соображать, а нахрена остальные строки. Даже такой записи уже было бы достаточно
foreach (var group in hash
        .GroupBy(rq => rq.IsRead)
        .Select(grp => new { IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds) }))
{
    MarkMsgsRead(
        _provider,
        group.Ids,
        group.IsRead);
}


Кстати, не поясните, что делает эта часть (какой тип возвращает return)? (У нас в проекте linq не используют)

            var groups = groupBy.Select(
                delegate(IGrouping<bool, MarkRequest> grp)
                    {
                        return new {IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds)};
                    }
                );
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[3]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:06
Оценка:
Здравствуйте, Andrey Rubayko, Вы писали:

AR> AN>
foreach (var group in hash

AR> AN>        .GroupBy(rq => rq.IsRead)
AR> AN>        .Select(grp => new { IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds) }))

AR> AN>    MarkMsgsRead(
AR> AN>        _provider,
AR> AN>        group.Ids,
AR> AN>        group.IsRead);


AR> AN>Незнаю как вы, но большой одной строки для foreach я как то слабо представляю, поэтому также не смог сразу врубиться, не говоря уж об обилии лямбд


AR> Вот тут как раз надо смотреть как работает механика на лямбда. Иначе у меня такое подозрение, что запрос энтот будет выполнятся на каждой итерации цикла. Возможно даже цикл получится бесконечным. Ну и помаркать сообщения можно бы было напрямую лямбда-запросом. Но это уже всякие извращения.


Что то у меня есть такое подозрение что foreach вызывает "enumerable-expression" только один раз.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:06
Оценка:
Здравствуйте, Sinix, Вы писали:

S> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


S> А CopyTo + запись префикса — слишком просто?

Вопрос не ко мне . Если есть желание, можете просто выложить Вашу версию.

S> За ref-ы,

У функции уже были параметры (без рефов), менять слишком много было просто запрещено.
S> допущение того, что bufferLength может быть меньше 0,
Пути господни неисповедимы
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:06
Оценка:
Здравствуйте, xobotik, Вы писали:

x>
 if (buffer != null)

x> Порадовало такое ощущение что код писал параноик)
Эээ... батенька вас надо с нашей QA группой познакомить
x> Да и на фига массив по ссылке передавать?)))
Я же говорю код тяжело понять Входной массив не обязательно будет "константой".

x> А можно ли постановку задачи, чтобы выложить свою версию метода?

Но проблемо. Кстати, эта функция раньше была гораздо проще.
Есть некоторый массив байт, который нужно в итоге переслать в выходной поток. Но перед этим нужно в начале добавить один байт.
Примечание:
Добавить байт в буфер вначале, до данных, 
непонятно как, так как при другом типе выходного потока байт добавлять не нужно, 
а данные приходят "снаружи".

Раньше, копировать данные абсолютно не хотелось и дополнительный байт просто выводился прямо в поток, а после все остальное. Однако оказалось, что минимум под виндовс 7 такой способ передачи резко не нравится приемнику он требовал передавать все сразу.
Кстати размер буфера не может быть больше 256 байт и в реале получается от 10 до 150 байт.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[4]: Как не надо писать код
От: Ziaw Россия  
Дата: 09.04.11 12:23
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Кстати, не поясните, что делает эта часть (какой тип возвращает return)? (У нас в проекте linq не используют)


AN>
            var groups = groupBy.Select(
AN>                delegate(IGrouping<bool, MarkRequest> grp)
AN>                    {
AN>                        return new {IsRead = grp.Key, Ids = grp.SelectMany(rq => rq.MsgIds)};
AN>                    }
AN>                );

AN>


возвращает анонимный класс с двумя полями bool IsRead и IEnumerable<T> Ids где T тип элемента в rq.MsgIds.
Re[3]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 12:25
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN> ST> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


AN> ST> [skiped]


AN> ST> AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


AN> ST> Более того, я осмелился этот код переписать. Вот что у меня вышло:


AN> А для NET 2.0 это тоже будет работать?

Будет, если либу загрузить...

А если не нужны "чужие сообщения" либо вообще какие либо сообщения?
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[4]: Как не надо писать код
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 09.04.11 15:15
Оценка:
Здравствуйте, AlexNek, Вы писали:


AN>> ST> AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


AN>> ST> Более того, я осмелился этот код переписать. Вот что у меня вышло:


AN>> А для NET 2.0 это тоже будет работать?

AN>Будет, если либу загрузить...

AN>А если не нужны "чужие сообщения" либо вообще какие либо сообщения?


Мне только кажется или ты общаешься сам с собой?
По поводу вопроса о NET 2.0: я же просто отрефакторил этот код слегка, после чего он стал на порядок проще. Единственное, что нужно добавить явную проверку аргументов с генерацией ArgumentException, а не использовать контракты (я, кстати, об этом в комментарии явно указал)

А по поводу ваших QA и паранойи: почему вы думаете, что лишние проверки улучшают качество кода? Они это качество, как раз таки ухудшают, ибо понять код сложнее, кода больше, вероятность ошибок возврастает, ведь вполне можно забыть добавить еще одну проверку при добавлении очередной строки кода.

Кстати, CopyTo здесь не подойдет, поскольку мы можем копировать из своего массива в свой же массив (там условие есть и вполне может быть, что newBuffer будет указывать на buffer), в результате мы получим выход за границу массива.

Да, и проверка на отрицательность длины тоже есть, но сделано это неявно здесь:
bufferLength = 1 + Math.Min(Math.Max(bufferLength, 0), (buffer != null) ? buffer.Length : 0);
Re[5]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 16:24
Оценка:
Здравствуйте, SergeyT., Вы писали:

ST> AN>> ST> AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


ST> AN>> ST> Более того, я осмелился этот код переписать. Вот что у меня вышло:


ST> AN>> А для NET 2.0 это тоже будет работать?


ST> AN>Будет, если либу загрузить...


ST> AN>А если не нужны "чужие сообщения" либо вообще какие либо сообщения?


ST> Мне только кажется или ты общаешься сам с собой?

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

ST> По поводу вопроса о NET 2.0:

просто было интересно, не поймите как критику.

ST> А по поводу ваших QA и паранойи: почему вы думаете, что лишние проверки улучшают качество кода?

Это видимо надо переносить в раздел "священные войны".

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

Как то связать не могу, если проверок не будет, значит вероятность появления ошибок уменьшается?
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[6]: Как не надо писать код
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 09.04.11 16:44
Оценка:
Здравствуйте, AlexNek, Вы писали:

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

AN>Как то связать не могу, если проверок не будет, значит вероятность появления ошибок уменьшается?

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

ST>> А по поводу ваших QA и паранойи: почему вы думаете, что лишние проверки улучшают качество кода?

AN>Это видимо надо переносить в раздел "священные войны".

Нет, не нужно Лучше почитать Совершенный код
Автор(ы): Стив Макконнелл

Опираясь на академические исследования, с одной стороны, и практический
опыт коммерческих разработок ПО — с другой, автор синтезировал из самых
эффективных методик и наиболее эффективных принципов ясное прагматичное
руководство. Каков бы ни был ваш профессиональный уровень, с какими бы
средствами разработками вы ни работали, какова бы ни была сложность вашего
проекта, в этой книге вы найдете нужную информацию, она заставит вас
размышлять и поможет создать совершенный код. Книга состоит из 35 глав,
предметного указателя и библиографии.
, Чистый код (немного о ней здесь), Рефакторинг ну и напоследок Объектно-ориентированное конструирование программных систем
Автор(ы): Бертран Мейер
Издательство: Русская Редакция
Цена: 807р.

Книга посвящена обоснованию и технологии применения объектного подхода при разработке программных систем. Основное внимание уделяется вопросам качества, повторного использования и расширяемости проектируемых систем. Рассматриваемый
, чтобы понять отличия защитного и контрактного программирования (кстати, даже в защитном программировании никто не параноит настолько, чтобы проверять одно и тоже десять раз в *одной* функции) и самим сделать вывод (или, опять таки, просто сравните два варианта кода).
Re[7]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 17:33
Оценка:
Здравствуйте, SergeyT., Вы писали:

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


ST> AN>Как то связать не могу, если проверок не будет, значит вероятность появления ошибок уменьшается?


ST> А ты сравни исходный код и мой, и скажи, в каком вероятность ошибок выше.

Исходный код сравнивать нечего его уже давно не существует в приведенном виде.

ST> Если следовать твоей логике, то вероятность ошибок в моем коде должна быть в 5 раз выше, ведь именно во столько раз там меньше проверок

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


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

ST> ST>> А по поводу ваших QA и паранойи: почему вы думаете, что лишние проверки улучшают качество кода?


ST> AN>Это видимо надо переносить в раздел "священные войны".


ST> Нет, не нужно Лучше почитать

если я и прочту то QA уж точно нет
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[8]: Как не надо писать код
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 09.04.11 18:42
Оценка:
Здравствуйте, AlexNek, Вы писали:

ST>> Если следовать твоей логике, то вероятность ошибок в моем коде должна быть в 5 раз выше, ведь именно во столько раз там меньше проверок


AN>Логика то как раз не моя (и кстати не такая)

AN>
кода больше, вероятность ошибок возрастает, ведь вполне можно забыть добавить еще одну проверку при добавлении очередной строки кода
AN>


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

AN>А хотел сказать, что не вижу связи между наличием "правильной" проверки и количеством ошибок.


Я имел ввиду, что в исходном примере, проверки "неправильные", в моем примере — они "правильные". "Неправильные" проверки — ухудшают качество, "правильные" проверки — улучшают.


ST>> ST>> А по поводу ваших QA и паранойи: почему вы думаете, что лишние проверки улучшают качество кода?


ST>> AN>Это видимо надо переносить в раздел "священные войны".


ST>> Нет, не нужно Лучше почитать

AN>если я и прочту то QA уж точно нет

Дать читать менеджменту, если он этого еще не читал. Если и он не осилит — уходить.
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 19:46
Оценка:
Здравствуйте, _FRED_, Вы писали:

FRE> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


FRE> 25 см?

Ну если это код, то я зелёный
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[9]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 19:46
Оценка:
Здравствуйте, SergeyT., Вы писали:

ST> ST>> Если следовать твоей логике, то вероятность ошибок в моем коде должна быть в 5 раз выше, ведь именно во столько раз там меньше проверок


ST> AN>Логика то как раз не моя (и кстати не такая)

ST> AN>
кода больше, вероятность ошибок возрастает, ведь вполне можно забыть добавить еще одну проверку при добавлении очередной строки кода
ST> AN>


ST> Я, если честно, запутался Я здесь имел ввиду следующее:

ST> попробуйте добавить еще какую-нибудь логику в исходный пример.
Ну если еще не забыли, исходный пример выложен под рубрикой "как не надо писать код"
Иначе говоря, нужно размышлять о чем то более обобщенном.
ST> Это потребует в каждом обращении к buffer или newBuffer добавлять проверки, что еще сильнее ухудшит качество кода
Почему потребует?
ST>и может привести к тому, что кто-то добавит логику без этой проверки и все поломает. Все это решается одной проверкой вначале метода.
где то вдалеке появился свет, но если можно было привести примерчик...
ST> AN>А хотел сказать, что не вижу связи между наличием "правильной" проверки и количеством ошибок.

ST> Я имел ввиду, что в исходном примере, проверки "неправильные", в моем примере — они "правильные". "Неправильные" проверки — ухудшают качество, "правильные" проверки — улучшают.

Я так и подумал, когда писал, что нужно определить понятие "правильный" в данном контексте. Я имел в виду, что если вместо ожидаемой ("правильной") проверки "а!=null" будет написано "а==null".
Однако Ваша идея понятна.

ST> ST>> ST>> А по поводу ваших QA и паранойи: почему вы думаете, что лишние проверки улучшают качество кода?


ST> ST>> AN>Это видимо надо переносить в раздел "священные войны".


ST> ST>> Нет, не нужно Лучше почитать


ST> AN>если я и прочту то QA уж точно нет


ST> Дать читать менеджменту, если он этого еще не читал. Если и он не осилит — уходить.

Проблема в том, что данные статьи они в принципе не смогут прочитать.
Ну а если уходить по подобным поводам, то надо каждый месяц менять работу
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[3]: Как не надо писать код
От: xobotik Россия  
Дата: 09.04.11 20:38
Оценка:
Здравствуйте, AlexNek, Вы писали:

То есть допустим на входе массив, необходимо сместить данные на одну позицию влево и добавить что-то в array[0]?
С уважением!
Re: Как точно не надо писать код
От: xobotik Россия  
Дата: 09.04.11 20:51
Оценка:
Здравствуйте, AlexNek, Вы писали:

Хорошо, что один только метод кривой, а когда весь проект, это ужас просто =)
Вот пример "КАК ТОЧНО НЕ НАДО ПИСАТЬ КОД":

P.S. Кода много (около 1000 строк). Проект не буду высылать, там вообще ужас.
Для разогрева, есть такой компонент графический Memo в Borland C++ Builder,
ну так вот в этом коде одному из компонентов Memo присвоено свойство Visible = false и используется как буфер при расчетах ))

жесть.rar Размер 6 кб.
С уважением!
Re[2]: Как точно не надо писать код
От: AlexNek  
Дата: 09.04.11 21:18
Оценка:
Здравствуйте, xobotik, Вы писали:

x> Хорошо, что один только метод кривой, а когда весь проект, это ужас просто =)

Ну этого просто нельзя допускать
x> Вот пример "КАК ТОЧНО НЕ НАДО ПИСАТЬ КОД":
Ну самую "смешную" функцию можно было

x> P.S. Кода много (около 1000 строк).

У нас немного разные понятия о много кода 1000 строк для одного файла, еще можно сказать много. Но называть проектом 1000 строк кода...
x> Проект не буду высылать, там вообще ужас.
x> Для разогрева, есть такой компонент графический Memo в Borland C++ Builder,
x> ну так вот в этом коде одному из компонентов Memo присвоено свойство Visible = false и используется как буфер при расчетах ))
Для Борланда непохоже, наверное стащили где то

x> жесть.rar Размер 6 кб.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[4]: Как не надо писать код
От: AlexNek  
Дата: 09.04.11 21:18
Оценка:
Здравствуйте, xobotik, Вы писали:

x> То есть допустим на входе массив, необходимо сместить данные на одну позицию влево и добавить что-то в array[0]?

Массив 1,2,3,4,5
Результат 99,1,2,3,4,5
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[3]: Как точно не надо писать код
От: xobotik Россия  
Дата: 09.04.11 21:27
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


x>> Хорошо, что один только метод кривой, а когда весь проект, это ужас просто =)

AN>Ну этого просто нельзя допускать

Да нельзя, ну что поделаешь, когда тебе дают задание рефакторить сие чудо)

x>> Вот пример "КАК ТОЧНО НЕ НАДО ПИСАТЬ КОД":

AN>Ну самую "смешную" функцию можно было

x>> P.S. Кода много (около 1000 строк).

AN>У нас немного разные понятия о много кода 1000 строк для одного файла, еще можно сказать много. Но называть проектом 1000 строк кода...

Гавно-кода и 1000 строк много)

x>> Проект не буду высылать, там вообще ужас.

x>> Для разогрева, есть такой компонент графический Memo в Borland C++ Builder,
x>> ну так вот в этом коде одному из компонентов Memo присвоено свойство Visible = false и используется как буфер при расчетах ))

AN>Для Борланда непохоже, наверное стащили где то

Не я писал, точно)

P.S. Ну вы меня поняли)) Спасибо за внимание )
С уважением!
Re[4]: Как точно не надо писать код
От: AlexNek  
Дата: 09.04.11 21:41
Оценка:
Здравствуйте, xobotik, Вы писали:

x> x>> Хорошо, что один только метод кривой, а когда весь проект, это ужас просто =)


x> AN>Ну этого просто нельзя допускать


x> Да нельзя, ну что поделаешь, когда тебе дают задание рефакторить сие чудо)

Мои соболезнования.
В таком случае наверное быстрее будет все с нуля написать.
Был такой вариант, кода правда побольше было. Один человек занялся оптимизацией кода в рабочей программе, другой начал разработку с нуля.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[5]: Как точно не надо писать код
От: xobotik Россия  
Дата: 09.04.11 22:20
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


x>> x>> Хорошо, что один только метод кривой, а когда весь проект, это ужас просто =)


x>> AN>Ну этого просто нельзя допускать


x>> Да нельзя, ну что поделаешь, когда тебе дают задание рефакторить сие чудо)

AN>Мои соболезнования.
Не, я это послал куда подальше =)
AN>В таком случае наверное быстрее будет все с нуля написать.
Быстрее, когда есть постановка задачи)
AN>Был такой вариант, кода правда побольше было. Один человек занялся оптимизацией кода в рабочей программе, другой начал разработку с нуля.
Класс, персонал большой значит )
С уважением!
Re[3]: Как не надо писать код
От: Олег К.  
Дата: 09.04.11 22:42
Оценка:
AN>Чтобы понять как работает также нужно напрягаться.
AN>Называется "экономия строк"

Особенно любит впихнуть как можно больше в одну строку местный мыщьх. Просто обожает оператор "запятая." Это, видать, его последователи.

Вообще считаю, что у человека должно быть развито чувство вкуса, чувство меры и чувство прекрасного (как бы напыщенно это не звучало) чтобы писать понятный код.
Re[6]: Как точно не надо писать код
От: AlexNek  
Дата: 09.04.11 22:55
Оценка:
Здравствуйте, xobotik, Вы писали:

x> x>> x>> Хорошо, что один только метод кривой, а когда весь проект, это ужас просто =)


x> x>> AN>Ну этого просто нельзя допускать


x> x>> Да нельзя, ну что поделаешь, когда тебе дают задание рефакторить сие чудо)


x> AN>Мои соболезнования.


x> Не, я это послал куда подальше =)


Хорошо когда есть выбор.
x> AN>В таком случае наверное быстрее будет все с нуля написать.

x> Быстрее, когда есть постановка задачи)

Узнаю дядю Васю
x> AN>Был такой вариант, кода правда побольше было. Один человек занялся оптимизацией кода в рабочей программе, другой начал разработку с нуля.

x> Класс, персонал большой значит )

Все относительно, сколько бы народа не было его всегда не хватает.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[5]: Как не надо писать код
От: xobotik Россия  
Дата: 10.04.11 01:58
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


x>> То есть допустим на входе массив, необходимо сместить данные на одну позицию влево и добавить что-то в array[0]?

AN>Массив 1,2,3,4,5
AN>Результат 99,1,2,3,4,5
        // 1
        public static T[] AddToFirst<T>(this T[] array, T item)
        {
            if (array == null) return new T[0];

            T[] newArray = new T[array.Length + 1];
            newArray[0] = item;

            for (int i = 0; i < array.Length; i++)
            {
                newArray[i + 1] = array[i];
            }
            return newArray;
        }
        // 2
        public static void AddToFirst<T>(ref T[] array, T item)
        {
            if (array == null) return;

            T[] newArray = new T[array.Length + 1];
            newArray[0] = item;

            for (int i = 0; i < array.Length; i++)
            {
                newArray[i + 1] = array[i];
            }
            array = newArray;
        }

в первом варианте решения нравится сценарий вызова:
int[] array = new int[10];
array = array.AddToFirst(100);

Но метод 2 получше ибо по аналогии с другими классами .NET, методы имеющие слово Add в названии, все таки в основном возвращают void.
Да и в вашем случае, как я понял, массив необходимо передавать через ref.
Если конечно обобщенные методы не устраивают, а необходимо передавать массив byte,
то можно воспользоваться следующими материалами, там вроде как решаются похожие задачи с упором на производительность:
1) http://codelab.ru/task/cycle_shift/;
2) http://habrahabr.ru/blogs/algorithm/101059/;
3) http://devels.ru/?what=art&amp;p=486.
С уважением!
Re[6]: Как не надо писать код
От: AlexNek  
Дата: 10.04.11 10:47
Оценка:
Здравствуйте, xobotik, Вы писали:

x> Если конечно обобщенные методы не устраивают, а необходимо передавать массив byte,

x> то можно воспользоваться следующими материалами, там вроде как решаются похожие задачи с упором на производительность:
Спасибо, конечно. Но вопрос как решить задачу правильно возник спонтанно по "желанию читателей" Кстати, в ссылках ничего полезного не нашел.
x> 1) http://codelab.ru/task/cycle_shift/;
x> 2) http://habrahabr.ru/blogs/algorithm/101059/;
x> 3) http://devels.ru/?what=art&amp;p=486.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 10.04.11 10:47
Оценка:
Здравствуйте, Олег К., Вы писали:

ОК> Зачем создал этот топик? Зайди в соседний форум по плюсам. Там в девяти топиках из десяти увидишь как не надо писать код.

Вообще то для учебных целей Может любители "оптимизации" заглянут
А плюсов я объелся в свое время, потому совсем не тянет туда ходить.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[4]: Как не надо писать код
От: AlexNek  
Дата: 10.04.11 10:47
Оценка:
Здравствуйте, Олег К., Вы писали:

ОК> AN>Чтобы понять как работает также нужно напрягаться.

ОК> AN>Называется "экономия строк"

ОК> Особенно любит впихнуть как можно больше в одну строку местный мыщьх. Просто обожает оператор "запятая." Это, видать, его последователи.

Я как раз и зациклился на этом коде именно из-за этого (оператор "запятая.") Скобочку справа не заметил
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[6]: Как не надо писать код
От: AlexNek  
Дата: 10.04.11 11:16
Оценка:
Здравствуйте, xobotik, Вы писали: (не могу найти исходное сообщение)

x> x>> То есть допустим на входе массив, необходимо сместить данные на одну позицию влево и добавить что-то в array[0]?


x> AN>Массив 1,2,3,4,5

x> AN>Результат 99,1,2,3,4,5

x>


x> public static T[] AddToStart<T>(this T[] array, T item)

x> {
x> if (array == null) throw new ArgumentNullException("array");

x> T[] newArray = new T[array.Length + 1];

x> newArray[0] = item;

x> for (int i = 0; i < array.Length; i++)

x> {
x> newArray[i + 1] = array[i];
x> }
x> return newArray;
x> }
x>

x> Конечно можно воспользоваться встроенными методами, но мне кажется в таком представлении понять метод не затруднит.


Как минимум вы убрали длину данных, никто не говорил что длина буфера== длине данных.
Кроме этого, для чего генерики? Речь шла о выводе байт (и только байт).
Ну и создавать каждый раз массив несколько накладно по времени, как мне кажется.
Для информации — функция реализует один из методов интерфейса.
Re[7]: Как не надо писать код
От: xobotik Россия  
Дата: 10.04.11 18:36
Оценка:
Здравствуйте, samius, Вы писали:

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


X>>Если конечно обобщенные методы не устраивают, а необходимо передавать массив byte,

X>>то можно воспользоваться следующими материалами, там вроде как решаются похожие задачи с упором на производительность:
X>>1) http://codelab.ru/task/cycle_shift/;
X>>2) http://habrahabr.ru/blogs/algorithm/101059/;
X>>3) http://devels.ru/?what=art&amp;p=486.

S>1ая и 3яя ссылки — ротация массивов, которая делается без использования дополнительной памяти. Для чего тут эти ссылки, если массив придется пересоздавать для добавления одного элемента? Ротация тут не нужна, ибо можно сделать копирование.

S>2-ая ссылка вообще о ротации битов
S>

Да чет в 6 утра затупил=) просто изначально хотел сделать так изменить размер массива (Array.Resize(array, array.Length + 1)), потом сместить вправо все элементы на одну позицию (для этого можно обобщить ротацию).
С уважением!
Re[7]: Как не надо писать код
От: xobotik Россия  
Дата: 10.04.11 18:36
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


x>> Если конечно обобщенные методы не устраивают, а необходимо передавать массив byte,

x>> то можно воспользоваться следующими материалами, там вроде как решаются похожие задачи с упором на производительность:
AN>Спасибо, конечно. Но вопрос как решить задачу правильно возник спонтанно по "желанию читателей" Кстати, в ссылках ничего полезного не нашел.

Да ссылки не те кинул =)
С уважением!
Re[8]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 10.04.11 18:39
Оценка:
Здравствуйте, xobotik, Вы писали:

X>Да чет в 6 утра затупил=) просто изначально хотел сделать так изменить размер массива (Array.Resize(array, array.Length + 1)), потом сместить вправо все элементы на одну позицию (для этого можно обобщить ротацию).


Resize это уже копирование, только без возможности указать индекс в целевом массиве.
Re[7]: Как не надо писать код
От: xobotik Россия  
Дата: 10.04.11 18:41
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Как минимум вы убрали длину данных, никто не говорил что длина буфера== длине данных.


Не понял) Вы о чем ?)

AN>Кроме этого, для чего генерики? Речь шла о выводе байт (и только байт).


T -> byte не проблема поменять )

AN>Ну и создавать каждый раз массив несколько накладно по времени, как мне кажется.


А как без создания дополнительного массива решать данную задачу ? )

AN>Для информации — функция реализует один из методов интерфейса.


Не понял)

P.S. Сообщение удалял =)
С уважением!
Re[9]: Как не надо писать код
От: xobotik Россия  
Дата: 10.04.11 18:45
Оценка:
Здравствуйте, samius, Вы писали:

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


X>>Да чет в 6 утра затупил=) просто изначально хотел сделать так изменить размер массива (Array.Resize(array, array.Length + 1)), потом сместить вправо все элементы на одну позицию (для этого можно обобщить ротацию).


S>Resize это уже копирование, только без возможности указать индекс в целевом массиве.


В курсе =)
С уважением!
Re[8]: Как не надо писать код
От: AlexNek  
Дата: 10.04.11 19:09
Оценка:
Здравствуйте, xobotik, Вы писали:

x> AN>Как минимум вы убрали длину данных, никто не говорил что длина буфера== длине данных.


x> Не понял) Вы о чем ?)

Там в параметрах функции вроде была еше длина данных. Я о том что если переделывать функцию желательно оставаться в пределах ее старых параметров.

x> AN>Кроме этого, для чего генерики? Речь шла о выводе байт (и только байт).


x> T -> byte не проблема поменять )

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

x> AN>Ну и создавать каждый раз массив несколько накладно по времени, как мне кажется.


x> А как без создания дополнительного массива решать данную задачу ? )

Довольно просто, размер буфера в 99.999% случаях меньше длины данных. Новый буфер создается только для теоретического случая когда буфера недостаточно.

x> AN>Для информации — функция реализует один из методов интерфейса.


x> Не понял)

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

x> P.S. Сообщение удалял =)

Теперь уже поняли, появилась новая проблема работы с оффлайн бровсерами
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[8]: Как не надо писать код
От: AlexNek  
Дата: 10.04.11 19:09
Оценка:
Здравствуйте, xobotik, Вы писали:

x> x>> Если конечно обобщенные методы не устраивают, а необходимо передавать массив byte,

x> x>> то можно воспользоваться следующими материалами, там вроде как решаются похожие задачи с упором на производительность:

x> AN>Спасибо, конечно. Но вопрос как решить задачу правильно возник спонтанно по "желанию читателей" Кстати, в ссылках ничего полезного не нашел.


x> Да ссылки не те кинул =)

Сорри, это было мне не узнать.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[9]: Как не надо писать код
От: xobotik Россия  
Дата: 10.04.11 19:36
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Там в параметрах функции вроде была еше длина данных. Я о том что если переделывать функцию желательно оставаться в пределах ее старых параметров.


public void WriteTransformation(ref byte[] buffer, ref int bufferLength, WriteByteHandler writeByteHandler)


То есть int bufferLength это длина совершенно другого какого то буфера?) То есть buffer.Length != bufferLength?

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


Согласен, но вы же сами сказали http://rsdn.ru/forum/dotnet/4227826.1.aspx
Автор: AlexNek
Дата: 10.04.11


AN>Довольно просто, размер буфера в 99.999% случаях меньше длины данных. Новый буфер создается только для теоретического случая когда буфера недостаточно.


То есть задача состоит в следующем:
есть какие либо данные, есть длина этих данных, есть константа PREFIX. Данные содержаться в массиве buffer длиной bufferLength -> N, сам массив длиной buffer.Length -> M. Необходимо добавить в начало PREFIX. Если N == M || N > M, то создаем новый массив, копируем все данные в новый массив, добавляем PREFIX (и эта ситуация с вероятностью 0.001). Если N < M смещаем данные в исходном массиве buffer на одну позицию вправо и записываем PREFIX в начало. Так же необходимо вернуть новую длину данных, а это всегда N + 1.

Следуя из сигнатуры метода, buffer -> массив, в котором содержаться данные длины bufferLength это так ?

AN>Это по поводу статика. Если нет использования this, еще не значит что можно делать функцию статик.

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

Просто не понял постановки задачи=)

x>> P.S. Сообщение удалял =)

AN>Теперь уже поняли, появилась новая проблема работы с оффлайн бровсерами

Не понял)
С уважением!
Re[2]: Как не надо писать код
От: Lloyd Россия  
Дата: 10.04.11 20:04
Оценка:
Здравствуйте, SergeyT., Вы писали:

ST>Более того, я осмелился этот код переписать. Вот что у меня вышло:


ST>
ST>public byte[] WriteTransformation(byte[] buffer, int bufferLength)

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

ST>{
ST>    // Выделяем проверку предусловий в отдельный блок, что на порядок упрощает весь остальной код.

И возможно ломает существующий код. :)

ST>    // Контракты просто упрощают запись, но никто не мешает проверить предусловия руками.
ST>    Contract.Requires(buffer != null);
ST>    Contract.Requires(bufferLength >= 0);
ST>    Contract.Ensures(Contract.Result<byte[]>() != null);

Ни одного из этих предусловий нет в коде.

ST>    // Прежде всего убираем не используемый параметр, 

Неиспользуемый? 
[q]
if (writeByteHandler != null)
[/q]

ST>если же он используется, то добавляем
ST>    // соответствующее предусловие.

Какое? И что вы будете возвращать, если writeByteHandler == null. У вас же Contract.Ensures(Contract.Result<byte[]>() != null) :)

ST>    // А теперь демонстрируем уличную магию того, как проверка предусловий упрощает код:
ST>    // Было: bufferLength = 1 + Math.Min(Math.Max(bufferLength, 0), (buffer != null) ? buffer.Length : 0);
ST>    // Меняем: (buffer != null) ? buffer.Length : 0 --> buffer.Length, благодаря buffer != null
ST>    // Меняем: Math.Max(bufferLength, 0) --> bufferLength, благодаря bufferLength >= 0
ST>    // Добавляем комментарий и вот, что мы получаем в итоге:
            
ST>    // Необходимость +1 обусловлена тем, что в нулевой байт выходного буфера мы поместим PREFIX
ST>    bufferLength = 1 + Math.Min(bufferLength, buffer.Length);

Переиспользование переменной для разных нужд. Фаулер негодуэ. :)

ST>    byte[] newBuffer;

ST>    // Теперь меняем следующий код:
ST>    // Было: if (bufferLength - 1 < ((buffer != null) ? buffer.Length : 0))
ST>    // Проверка buffer != null, уже не нужна
ST>    // Получаем: if (buffer.Length > bufferLength - 1)
ST>    // Заменяем > на >=:
ST>    // if (buffer.Lengh >= bufferLength)
ST>    // Инвертируем логику, поскольку она проще
ST>    // Результат: if (buffer.Lenfth < bufferLenfth) ...
ST>    // Добавляем комментарий и вот, что получаем в результате:

ST>    // Нам нужно удостовериться, что в исходном массиве есть место под дополнительный
ST>    // байт префикса:
ST>    if (buffer.Length < bufferLength )
ST>    {
ST>        newBuffer = new byte[bufferLength];
ST>    }
ST>    else
ST>    {
ST>        newBuffer = buffer;
ST>    }

ST>    // Все, что удалось улучшить в этом коде, так это избавиться от лишних
ST>    // проверок и добавить комментарий, поясняющий причину перебора элементов
ST>    // "справа". Кстати, Array.CopyTo здесь не подойдет, поскольку он копирует
ST>    // *все* элементы массива, а реальный размер массива buffer может быть большим

Зато подойдет Array.Copy :)

ST>    // Добавляем комментарий:
ST>    // Теперь нам нужно скопировать все элементы из массива buffer в newBuffer, сместив
ST>    // каждый из них на  один индекс вправо, чтобы в нулевой индекс поместить PREFIX

Имхо, единственный нетривиальный момент этого кода (обратный ход цикла) вы и не удосужились откомментировать.

ST>    for (int i = bufferLength - 1; i > 0; i--)
ST>    {
ST>        newBuffer[i] = buffer[i - 1];
ST>    }

ST>    // Здесь тоже проверка уже не нужна
ST>    newBuffer[0] = PREFIX;

ST>    // У нас все еще есть проблема, поскольку в некоторых случаях мы меняем переданный буфер,
ST>    // так что, если размер этого массива обычно небольшой, то я бы предпочел, чтобы всегда
ST>    // возвращался новый объект.
ST>    // Неизменяемость (или имутабельность) - это отличная техника программирования!
ST>    return newBuffer;
ST>}
ST>
Re[3]: Как не надо писать код
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 10.04.11 21:41
Оценка:
Здравствуйте, Lloyd, Вы писали:

ST>>
ST>>public byte[] WriteTransformation(byte[] buffer, int bufferLength)


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


Ну, тут каждому свое. Я бы сделал buffer неизменяемым если это возможно (т.е. не накладно). А то, что мы все равно можем изменить передаваемый буфер (путем изменения его содержимого, а не переменной) это тоже плохо. Я, кстати, об этом в самом низу сказал.

ST>>{

ST>> // Выделяем проверку предусловий в отдельный блок, что на порядок упрощает весь остальной код.

L>И возможно ломает существующий код.


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

ST>> // Контракты просто упрощают запись, но никто не мешает проверить предусловия руками.

ST>> Contract.Requires(buffer != null);
ST>> Contract.Requires(bufferLength >= 0);
ST>> Contract.Ensures(Contract.Result<byte[]>() != null);

L>Ни одного из этих предусловий нет в коде.

Я осмелился их добавить. Кстати, все предусловия есть в коде в неявном виде. Посмотри внимательно на все проверки buffer != null. Фактически — это и есть предусловие. Т.е. если buffer == null, то никакая работа в методе не выполнится. Кроме того, проверка на bufferLength >= 0 тоже присутствует. Она зашита в этом:
bufferLength = 1 + Math.Min(Math.Max(bufferLength, 0), (buffer != null) ? buffer.Length : 0);

Только разница в этом случае в том, что если buffer == null — мы ничего не делаем, а если bufferLength < 0 — то мы сей факт просто игнорируем.

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

ST>> // Прежде всего убираем не используемый параметр,


L>Неиспользуемый?

L>

L>if (writeByteHandler != null)


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

ST>>если же он используется, то добавляем

ST>> // соответствующее предусловие.

L>Какое? И что вы будете возвращать, если writeByteHandler == null. У вас же Contract.Ensures(Contract.Result<byte[]>() != null)


Если он используется и является ключевым для работы метода, то я добавляю предусловие writeByteHandler != null. Если это не является предусловием, например, если этот делегат используется для переопределения поведения по-умолчанию (может для замены того самого первого байта), то предусловие убираем. При этом это никак не влияет на постусловие.

Кроме того, повторюсь еще раз: использование Code Contracts в этом примере — это лишь механизм, а не пошаговая инструкция. Ты можешь заменить Code Contracts на генерацию исключений или просто на выход из метода. Да это будет не пофеншую с точки зрения дядьки Мейера, но тем не менее, неявный контракт метода будет присутствовать, просто он будет звучать не как: "если вы мне передали хрень — я сгенерю исключение", а так: "если вы мне передали хрень — я ничего не буду делать и просто верну управление". Решать нужно на месте, в большинстве случаев я бы генерил исключение, как бы поступл ты — хз.

ST>> // А теперь демонстрируем уличную магию того, как проверка предусловий упрощает код:

ST>> // Было: bufferLength = 1 + Math.Min(Math.Max(bufferLength, 0), (buffer != null) ? buffer.Length : 0);
ST>> // Меняем: (buffer != null) ? buffer.Length : 0 --> buffer.Length, благодаря buffer != null
ST>> // Меняем: Math.Max(bufferLength, 0) --> bufferLength, благодаря bufferLength >= 0
ST>> // Добавляем комментарий и вот, что мы получаем в итоге:

ST>> // Необходимость +1 обусловлена тем, что в нулевой байт выходного буфера мы поместим PREFIX

ST>> bufferLength = 1 + Math.Min(bufferLength, buffer.Length);

L>Переиспользование переменной для разных нужд. Фаулер негодуэ.


Да, я тут заметку по этому поводу ваяю, там я уже добавил newBufferLength. Прости, посыпаю голову пеплом, что сразу не зделал все, как нужно

ST>> // Все, что удалось улучшить в этом коде, так это избавиться от лишних

ST>> // проверок и добавить комментарий, поясняющий причину перебора элементов
ST>> // "справа". Кстати, Array.CopyTo здесь не подойдет, поскольку он копирует
ST>> // *все* элементы массива, а реальный размер массива buffer может быть большим

L>Зато подойдет Array.Copy


Ага. Вот эту перегруженную версию метода Copy я что-то проглядел.

ST>> // Добавляем комментарий:

ST>> // Теперь нам нужно скопировать все элементы из массива buffer в newBuffer, сместив
ST>> // каждый из них на один индекс вправо, чтобы в нулевой индекс поместить PREFIX

L>Имхо, единственный нетривиальный момент этого кода (обратный ход цикла) вы и не удосужились откомментировать.


Опять, повторюсь, после ревизии я добавил коммент, что проход цикла справа обусловлен тем, что buffer и newBuffer могут указывать на один и тот же объект массива, хотя по новому коду понять причину этого уже несколько проще, не находишь? Но, конечно же, вариант с Copy идеальный, ибо мы получаем такой себе memmove.

ST>> for (int i = bufferLength — 1; i > 0; i--)

ST>> {
ST>> newBuffer[i] = buffer[i — 1];
ST>> }

ST>> // Здесь тоже проверка уже не нужна

ST>> newBuffer[0] = PREFIX;
Re[11]: Как не надо писать код
От: xobotik Россия  
Дата: 10.04.11 22:22
Оценка:
Здравствуйте, AlexNek, Вы писали:

x>> То есть int bufferLength это длина совершенно другого какого то буфера?) То есть buffer.Length != bufferLength?

AN>Правильнее было было бы назвать эту переменную по другому, типа "длина данных" в буфере.

Вы правы=)

x>> Согласен, но вы же сами сказали http://rsdn.ru/forum/dotnet/4227826.1.aspx
Автор: AlexNek
Дата: 10.04.11


AN>А что в том примере неправильно?


Да все правильно, просто я его дословно понял, поэтому и написал метод AddToFirst))

AN>Вы наверное еще не были в разделе "открытые проекты" и RSDN@Home?


Неа =) надо покурить этот хоум=)

AN>Я тоже раньше не был, но потом попробовал и весьма понравилось. Кстати, огромнейший простор для применения своих сил. Рекомендую начать ознакомление с avalon-а, а потом можно приняться и за янус. Наоборот лучше не делать, останется неприятный осадок.


Avalon прикольная штука=)) буду юзать, спасибо =)

А по поводу задачки, ну вот вроде решил:
        public void WriteTransformation(ref byte[] buffer, ref int dataLength, WriteByteHandler handler)
        {
            if (buffer == null) return;
            if (dataLength < 0) return;
            if (handler == null) return;

            if (dataLength < buffer.Length)
            {
                for (int i = dataLength; i > 0; i--)
                {
                    buffer[i] = buffer[i - 1];
                }
                buffer[0] = PREFIX;
            }
            if (dataLength >= buffer.Length)
            {
                byte[] newArray = new byte[dataLength + 1];
                for (int i = 0; i < buffer.Length; i++)
                {
                    newArray[i + 1] = buffer[i];
                }
                newArray[0] = PREFIX;
                buffer = newArray;
            }
            dataLength++;
        }

P.S. Конечно можно было выделить как минимум один дополнительный метод это сдвиг элементов массива в право на N позиций,
но стоит задача в рамках одного метода реализовать, как я понял.
Так же конечно можно было воспользоваться встроенным методом Array.Copy вместо участка кода:
for (int i = 0; i < buffer.Length; i++)
{
    newArray[i + 1] = buffer[i];
}

код:
Array.Copy(buffer, 0, newArray, 1, buffer.Length);

но как-то нарушается эстетика всего метода, а конкретнее симметрия, чисто мое мнение =)
Да и еще не рассмотрел случай, когда передается пустой buffer, но dataLength отлична и больше нуля, надо ли рассматривать такой случай?
С уважением!
Re: Как не надо писать код
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 11.04.11 07:19
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно.


Один вопрос: человек до этого кодил на C или C++? А то у меня Deja vu.
getboost.codeplex.com
citylizard.codeplex.com
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 11.04.11 16:31
Оценка:
Здравствуйте, Powerz, Вы писали:

P> Задача: на вход поступает int, надо вернуть последнюю цифру.

P> Собственно шедевр (имя метода и входного параметра изменено, все совпадения чистая случайность):

P>
P> public static string GetX(int id)
P> {
P>     return id.ToString().Substring(id.ToString().Length - 1, 1);
P> }
P>


P> Писал не какой-нибудь джуниор, а программист-архитектор-тимлид.


P> Переписано так:


P>
P> public static int GetX(int id)
P> {
P>     return id % 10;
P> }
P>


Это шедевр нормальному человеку до такого не додуматься, а умному запросто.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 11.04.11 16:31
Оценка:
Здравствуйте, sergey_shandar, Вы писали:

s> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно.


s> Один вопрос: человек до этого кодил на C или C++? А то у меня Deja vu.

Мне это неизвестно. Обычно он пишет на Дельфях приложения несколько критичные ко времени выполнения.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[12]: Как не надо писать код
От: AlexNek  
Дата: 11.04.11 16:31
Оценка:
Здравствуйте, xobotik, Вы писали:

x> AN>Вы наверное еще не были в разделе "открытые проекты" и RSDN@Home?


x> Неа =) надо покурить этот хоум=)

Осторожно — можно подсесть капитально

x> А по поводу задачки, ну вот вроде решил:

Ну задачки для решения вроде не ставилось, но за прилежание
x>
x>         public void WriteTransformation(ref byte[] buffer, ref int dataLength, WriteByteHandler handler)
x>         {
x>             if (buffer == null) return;
x>             if (dataLength < 0) return;
x>             if (handler == null) return;

x>             if (dataLength < buffer.Length)
x>             {
x>                 for (int i = dataLength; i > 0; i--)
x>                 {
x>                     buffer[i] = buffer[i - 1];
x>                 }
x>                 buffer[0] = PREFIX;
x>             }
x>             if (dataLength >= buffer.Length)
x>             {
x>                 byte[] newArray = new byte[dataLength + 1];
x>                 for (int i = 0; i < buffer.Length; i++)
x>                 {
x>                     newArray[i + 1] = buffer[i];
x>                 }
x>                 newArray[0] = PREFIX;
x>                 buffer = newArray;
x>             }
x>             dataLength++;
x>         }
x>

x> P.S. Конечно можно было выделить как минимум один дополнительный метод это сдвиг элементов массива в право на N позиций,
x> но стоит задача в рамках одного метода реализовать, как я понял.
x> Так же конечно можно было воспользоваться встроенным методом Array.Copy вместо участка кода:
Что мне лично тут не нравиться
— вместо
if (dataLength < buffer.Length)
  {
     ...
  }
  if (dataLength >= buffer.Length)

лучше было бы.
if (dataLength < buffer.Length)
  {
     ...
  }
else

А то начинаешь мучительно думать,каким образом получается dataLength > buffer.Length и кстати, в этом случае, код будет неправильно работать.
— Для одного и того же действия используются различные имплементации.
— Старый алгоритм работы метода не был скопировал, а именно, что при "нулевом" буфере возвращается префикс.
x>
x> for (int i = 0; i < buffer.Length; i++)
x> {
x>     newArray[i + 1] = buffer[i];
x> }
x>

x> код:
x>
x> Array.Copy(buffer, 0, newArray, 1, buffer.Length);
x>

x> но как-то нарушается эстетика всего метода, а конкретнее симметрия, чисто мое мнение =)
x> Да и еще не рассмотрел случай, когда передается пустой buffer, но dataLength отлична и больше нуля, надо ли рассматривать такой случай?
Ценное замечания, старая функция на этом пролетает.
Надо рассматривать все что "выбьет" метод, может быть и спорно, на зато QA не будут получать повода для радости и уколок.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[2]: Как не надо писать код
От: Sinclair Россия https://github.com/evilguest/
Дата: 14.04.11 04:01
Оценка:
Здравствуйте, SergeyT., Вы писали:

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


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

ST>[skiped]

AN>>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


ST>Более того, я осмелился этот код переписать. Вот что у меня вышло:


Если я правильно понял, то передача buffer == null и bufferLength = 0 — корректна. В этом случае нужно вернуть буфер единичного размера с префиксом.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Как не надо писать код
От: Sinix  
Дата: 14.04.11 04:25
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Если я правильно понял, то передача buffer == null и bufferLength = 0 — корректна. В этом случае нужно вернуть буфер единичного размера с префиксом.

Но это нифига непонятно и неожиданно. Лучше явно декларировать свои намерения — отдельным методом.
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 14.04.11 16:11
Оценка:
Здравствуйте, Sinclair, Вы писали:

S> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


S> AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


S> Довольно много.

Как говорится, что и требовалось доказать
S> Из глупостей:
Они и должны были быть в подобном коде (под данной рубрикой) и хорошо что Вы их перечислили.
S> 1. Попытки на ходу исправить bufferLength. Зачем? Отрицательные размеры, а также размеры более длины переданного буфера не имеют физического смысла. Вместо того, чтобы пытаться их как-то скорректировать, нужно выбрасывать исключение — пусть вызывающая сторона исправляет свой код.
В данном случае важнее была работоспособность.
S> 2. Попытки схитрить с переиспользованием существующего буфера. Зачем? Это что, оптимизация? Для оптимизации нужны результаты профайлера. Судя по остальному коду, профайлер этого никогда не мерил. Ну так и незачем заниматься усложнением на ровном месте. Выделяйте буфер всегда. Дорогая операция здесь — копирование, которое происходит в любом случае. Выделение пары сотен байт из кучи в управляемой среде ничего не стоит.
Специальных исследований не проводил, но помнятся противоположные результаты.

S> 3. Повторение избыточных проверок. Это только запутывает код и мешает компилятору со средой проводить оптимизации. Проверили буфер на null один раз, в самом начале — и достаточно. Делать это в цикле тем более не имеет смысла.

if (newBuffer != null) if (buffer != null)

Уже только эту строку можно занести в шедевры "как не надо"
S> 4. Зачем растить столько ветвей в графе управления? DRY: достаточно ровно одной строки, которая приписывает префикс.
С последним предложеним как то не совсем понятно
S> 5. Отказ от использования встроенных средств. Array.Copy — то, что доктор прописал. Это мало того, что более понятно, так ещё и более оптимально (там внутри используется развёртка циклов и копирование как минимум по DWORD за раз). За побайтное копирование в 21 веке нужно бить логарифмической линейкой по пальцам.
Если предоставите линейку напрокат
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[4]: Как не надо писать код
От: AlexNek  
Дата: 16.04.11 10:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

S> AN>В данном случае важнее была работоспособность.


S> Я не понимаю, о какой работоспособности можно говорить в коде, где кто-то присылает массив длинной 10 и просит отправить 15 байт.

S> Значит, автор кода забыл добавить последние 5 байт, и в устройство в результате вашей "починки" уезжает мусор.
Вы не учли одной вещи. Что принимающая сторона на линии А всегда ожидает заголовок в ваши 5 байт.
S> Именно такие попытки "починить на ходу" отвечают за сверхъестественно выглядящие баги, которые ищутся годами. Поверьте мне — я в детстве тоже так делал.

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

S> AN>Специальных исследований не проводил, но помнятся противоположные результаты.


S> Результаты вам помнятся по С++.

Может быть. Сейчас решил чисто на шару проверить и получилось даже смешно
           (No new) Repeats 500000 buffer size 256 time 00:00:00.5496574
         (With new) Repeats 500000 buffer size 256 time 00:00:00.4979645
         * 
         * (No new) Repeats 500000 buffer size 512 time 00:00:01.0589830
         (With new) Repeats 500000 buffer size 512 time 00:00:00.9412769
         * 
         * (No new) Repeats 500000 buffer size 1024 time 00:00:02.1139021
         (With new) Repeats 500000 buffer size 1024 time 00:00:01.8606506
         * 
         * (No new) Repeats 100000 buffer size 4096 time 00:00:01.7431369
         (With new) Repeats 100000 buffer size 4096 time 00:00:01.5042657
         * 
         * (No new) Repeats 100000 buffer size 8192 time 00:00:03.3840202
         (With new) Repeats 100000 buffer size 8192 time 00:00:02.9811746

Надо бы еще IL глянуть
        public static void InitBuffer(byte[] buffer)
        {
            for (int i = 0; i < buffer.Length; i++)
            {
                buffer[i] = 0x55;
            }
        }

        private static void TestNoNew(int BufferLength, int RepeatCount)
        {
            byte[] buffer;
            Stopwatch timer = new Stopwatch();
            timer.Start();
            buffer = new byte[BufferLength];
            for (int i = 0; i < RepeatCount; i++)
            {
                InitBuffer(buffer);
            }

            timer.Stop();
            Console.WriteLine("(No new) Repeats {0} buffer size {1} time {2}", RepeatCount, BufferLength, timer.Elapsed);
        }

        private static void TestWithNew(int BufferLength, int RepeatCount)
        {
            byte[] buffer;
            Stopwatch timer = new Stopwatch();
            timer.Start();
            for (int i = 0; i < RepeatCount; i++)
            {
                buffer = new byte[BufferLength];
                InitBuffer(buffer);
            }

            timer.Stop();
            Console.WriteLine("(With new) Repeats {0} buffer size {1} time {2}", RepeatCount, BufferLength, timer.Elapsed);
        }

S> S>> 3. Повторение избыточных проверок. Это только запутывает код и мешает компилятору со средой проводить оптимизации. Проверили буфер на null один раз, в самом начале — и достаточно. Делать это в цикле тем более не имеет смысла.

S> AN>
if (newBuffer != null) if (buffer != null)

S> AN>Уже только эту строку можно занести в шедевры "как не надо"

S> Сама по себе строка ничего особенно плохого не содержит. Важен контекст.

С точки зрения форматирования мне страшно понравилось
S> S>> 4. Зачем растить столько ветвей в графе управления? DRY: достаточно ровно одной строки, которая приписывает префикс.

S> AN>С последним предложеним как то не совсем понятно


S> Посмотрите, сколько раз в исходном коде встречается строчка ...[0] = PREFIX.

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

S> S>> 5. Отказ от использования встроенных средств. Array.Copy — то, что доктор прописал. Это мало того, что более понятно, так ещё и более оптимально (там внутри используется развёртка циклов и копирование как минимум по DWORD за раз). За побайтное копирование в 21 веке нужно бить логарифмической линейкой по пальцам.


S> AN>Если предоставите линейку напрокат


S> Можете угрожать wireless-шнуром. Не знаю почему, но неопытные разработчики боятся его до судорог.

У нас сейчас другая страшилка: Будешь писать плохой код прийдет микрософт WER и заберет твою прогу.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[5]: Как не надо писать код
От: Sinclair Россия https://github.com/evilguest/
Дата: 16.04.11 13:19
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


S>> AN>В данном случае важнее была работоспособность.


S>> Я не понимаю, о какой работоспособности можно говорить в коде, где кто-то присылает массив длинной 10 и просит отправить 15 байт.

S>> Значит, автор кода забыл добавить последние 5 байт, и в устройство в результате вашей "починки" уезжает мусор.
AN>Вы не учли одной вещи. Что принимающая сторона на линии А всегда ожидает заголовок в ваши 5 байт.
AN>Добавка байт была не починкой, а заданием класса/функции. Приведенный код возник когда выяснилось, что посылка вначале заголовка, а потом основного сообщения приводит к ошибкам на некоторых конфигурациях. Исправлять пришлось тому кто это нашел

Я не понимаю, о чём вы говорите. Я говорю о том, что код, который отправляет буфер размером в 10 байт, устанавливая bufferLength = 15, заведомо некорректен. Понимаете? Вы в вашем коде вместо того, чтобы сразу упасть (гуглить по fail fast) отправляете 11 байт вместо 16ти. Это может некоторое время выглядеть работающим, но впоследствии приведёт к совершенно сверхъестественному поведению, которое вы будете чинить годами.


S>> Результаты вам помнятся по С++.

AN>Может быть. Сейчас решил чисто на шару проверить и получилось даже смешно
Мерили в релизе или в дебаге?

S>> S>> 3. Повторение избыточных проверок. Это только запутывает код и мешает компилятору со средой проводить оптимизации. Проверили буфер на null один раз, в самом начале — и достаточно. Делать это в цикле тем более не имеет смысла.


S>> AN>
if (newBuffer != null) if (buffer != null)

S>> AN>Уже только эту строку можно занести в шедевры "как не надо"

S>> Сама по себе строка ничего особенно плохого не содержит. Важен контекст.

AN>С точки зрения форматирования мне страшно понравилось
Ну, это уже мелкие красивости, типа i++ + ++i

S>> Посмотрите, сколько раз в исходном коде встречается строчка ...[0] = PREFIX.

AN>Должна быть ровно один раз
Виноват, посмотрел не в ваш код. Да, у вас это таки правильно
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Как не надо писать код
От: AlexNek  
Дата: 16.04.11 14:28
Оценка:
Здравствуйте, Sinclair, Вы писали:

S> S>> AN>В данном случае важнее была работоспособность.


S> S>> Я не понимаю, о какой работоспособности можно говорить в коде, где кто-то присылает массив длинной 10 и просит отправить 15 байт.

S> S>> Значит, автор кода забыл добавить последние 5 байт, и в устройство в результате вашей "починки" уезжает мусор.

S> AN>Вы не учли одной вещи. Что принимающая сторона на линии А всегда ожидает заголовок в ваши 5 байт.

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

S> Я не понимаю, о чём вы говорите. Я говорю о том, что код, который отправляет буфер размером в 10 байт, устанавливая bufferLength = 15, заведомо некорректен.

S> Понимаете? Вы в вашем коде вместо того, чтобы сразу упасть (гуглить по fail fast) отправляете 11 байт вместо 16ти. Это может некоторое время выглядеть работающим, но впоследствии приведёт к совершенно сверхъестественному поведению, которое вы будете чинить годами.
Не понимаю также при чем здесь 15/16 байт?

У нас есть специальные куски кода которым просто запрещено выкидывать исключения.
Ну как пример, вы не можете в книге причитать строку. Вместо того чтобы сказать строка не читается, ложи книгу назад (fail fast) мы читаем книгу дальше и просто помечаем строку красным цветом. По моему это более приемлимо для пользователя.

S> S>> Результаты вам помнятся по С++.


S> AN>Может быть. Сейчас решил чисто на шару проверить и получилось даже смешно


S> Мерили в релизе или в дебаге?

Дебаг. Можно и релиз глянуть... получше
  (No new) Repeats 100000 buffer size 8192 time 00:00:02.7632629
(With new) Repeats 100000 buffer size 8192 time 00:00:02.9427531
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[2]: Как не надо писать код
От: MaximUN  
Дата: 21.04.11 16:04
Оценка:
Здравствуйте, SergeyT., Вы писали:

ST>Более того, я осмелился этот код переписать. Вот что у меня вышло:


ST>
ST>public byte[] WriteTransformation(byte[] buffer, int bufferLength)
ST>{
........
ST>}
ST>


В мне кажется ваш код ничем не лучше изначального. Слишком уж сложно для такой довольно тривиальной (правда с несколькими вырожденными случаями) операции. Комментариев — примерно столько же, сколько и кода.
Рядом есть вариант от Sinclair, ИМХО в разы лучше.
Re[7]: Как не надо писать код
От: HowardLovekraft  
Дата: 22.04.11 05:46
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>У нас есть специальные куски кода которым просто запрещено выкидывать исключения.

Т.е. даже если все хреново, и задача не выполнена, притворись, что все хорошо?
А если исключение выбросит сторонний код, используемый вашим кодом?

Re[8]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 08:50
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

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


AN>>У нас есть специальные куски кода которым просто запрещено выкидывать исключения.

HL>Т.е. даже если все хреново, и задача не выполнена, притворись, что все хорошо?
HL>А если исключение выбросит сторонний код, используемый вашим кодом?

HL>

Задача выполнена, но с ошибками. вроде пример с чтением книги приводил.
Возьмер допусти OCR прогу. Не может она распознать один символ и выкидывает при этом исключение — "Стор. Не могу распознать символ". Вам это понравится
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[10]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 09:29
Оценка:
Здравствуйте, samius, Вы писали:

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


AN>>Задача выполнена, но с ошибками. вроде пример с чтением книги приводил.

AN>>Возьмер допусти OCR прогу. Не может она распознать один символ и выкидывает при этом исключение — "Стор. Не могу распознать символ". Вам это понравится

S>По-вашему исключения придумали что бы морочить ими голову пользователям?

Я только говорю, что не следует все мешать в одном корыте
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[11]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 10:19
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


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


AN>>>Задача выполнена, но с ошибками. вроде пример с чтением книги приводил.

AN>>>Возьмер допусти OCR прогу. Не может она распознать один символ и выкидывает при этом исключение — "Стор. Не могу распознать символ". Вам это понравится

S>>По-вашему исключения придумали что бы морочить ими голову пользователям?

AN>Я только говорю, что не следует все мешать в одном корыте

Вот и не мешайте все в одно корыто. На примере OCR почувствуйте разницу между тем когда подали данные с нераспознаваемым символом, и тем когда подали поток данных недостаточной длины.
Re[13]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 10:40
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


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


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


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


AN>>>>>Задача выполнена, но с ошибками. вроде пример с чтением книги приводил.

AN>>>>>Возьмер допусти OCR прогу. Не может она распознать один символ и выкидывает при этом исключение — "Стор. Не могу распознать символ". Вам это понравится

S>>>>По-вашему исключения придумали что бы морочить ими голову пользователям?

AN>>>Я только говорю, что не следует все мешать в одном корыте

S>>Вот и не мешайте все в одно корыто. На примере OCR почувствуйте разницу между тем когда подали данные с нераспознаваемым символом, и тем когда подали поток данных недостаточной длины.

AN>Так что надо вывалить исключение и сказать пшел вон?
Сначала надо уловить разницу между тем, что является корректным набором данных для метода и нет. В случае некорректного формата данных нужно кидать исключение сразу, так быстрее найдете то место, где они становятся некорректными. Вам Sinclair дал ссылку на FailFast.

AN>По мне, так лучше показать пустую страницу и написать внутри что ее невозможно обработать.

Исключение разве мешает это сделать?

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

Кто этот смысл выдумал?

Вообще не пойму, причем тут страницы, до сих пор речь шла о WriteTransformation
Re[14]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 10:47
Оценка:
Здравствуйте, samius, Вы писали:

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


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


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


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


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


AN>>>>>>Задача выполнена, но с ошибками. вроде пример с чтением книги приводил.

AN>>>>>>Возьмер допусти OCR прогу. Не может она распознать один символ и выкидывает при этом исключение — "Стор. Не могу распознать символ". Вам это понравится

S>>>>>По-вашему исключения придумали что бы морочить ими голову пользователям?

AN>>>>Я только говорю, что не следует все мешать в одном корыте

S>>>Вот и не мешайте все в одно корыто. На примере OCR почувствуйте разницу между тем когда подали данные с нераспознаваемым символом, и тем когда подали поток данных недостаточной длины.

AN>>Так что надо вывалить исключение и сказать пшел вон?
S>Сначала надо уловить разницу между тем, что является корректным набором данных для метода и нет. В случае некорректного формата данных нужно кидать исключение сразу, так быстрее найдете то место, где они становятся некорректными. Вам Sinclair дал ссылку на FailFast.
Я специально привел пример, когда этого не следует делать.

AN>>По мне, так лучше показать пустую страницу и написать внутри что ее невозможно обработать.

S>Исключение разве мешает это сделать?
Да иногда может.

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

S>Кто этот смысл выдумал?
Наши принципы работы с пользователем

S>Вообще не пойму, причем тут страницы, до сих пор речь шла о WriteTransformation

Просто как более понятный пример
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[16]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 11:19
Оценка:
Здравствуйте, samius, Вы писали:

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


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


AN>>>>Так что надо вывалить исключение и сказать пшел вон?

S>>>Сначала надо уловить разницу между тем, что является корректным набором данных для метода и нет. В случае некорректного формата данных нужно кидать исключение сразу, так быстрее найдете то место, где они становятся некорректными. Вам Sinclair дал ссылку на FailFast.
AN>>Я специально привел пример, когда этого не следует делать.
S>Этот пример не имеет отношения к случаю проверки аргументов WriteTransformation
Это вполне может быть Вашим мнением. У меня оно несколько другое.

AN>>>>По мне, так лучше показать пустую страницу и написать внутри что ее невозможно обработать.

S>>>Исключение разве мешает это сделать?
AN>>Да иногда может.
S>Иногда может что?
Выдача исключения в большинстве случаев подразумевает переход на другой путь, в частности
показ диалога сообщения об ошибке и аврийное прерывания текущей операции.
AN>>>>Смысл в том что блок распознавания страниц должен всегда выдавать результат, а не передавать исключение наверх, те исключения просто обрабатываются "локально"
S>>>Кто этот смысл выдумал?
AN>>Наши принципы работы с пользователем
S>Вашь пользователь работает с WriteTransformation напрямую?
Конечно нет, но эта функция отностися к блоку не имеющему права выдавать исключения.

S>>>Вообще не пойму, причем тут страницы, до сих пор речь шла о WriteTransformation

AN>>Просто как более понятный пример
S>Вы его неверно трактуете.
Тут вопрос кто его неправильно трактует. Возможно мы его понимает по разному.
S>Если все методы приложения будут гнать пургу в ответ на пургу во входных данных, ваше приложение просто будет молча делать пургу вместо того что ожидает пользователь.
никто не ведет речь о всех методах, есть просто различные части с различным "поведением".
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[18]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 12:26
Оценка:
Здравствуйте, samius, Вы писали:

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


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


AN>>>>Я специально привел пример, когда этого не следует делать.

S>>>Этот пример не имеет отношения к случаю проверки аргументов WriteTransformation
AN>>Это вполне может быть Вашим мнением. У меня оно несколько другое.
S>очевидно
И при этом я не хочу утверждать что мое правильное или Ваше нет.

AN>>>>Да иногда может.

S>>>Иногда может что?
AN>>Выдача исключения в большинстве случаев подразумевает переход на другой путь, в частности
AN>>показ диалога сообщения об ошибке и аврийное прерывания текущей операции.
S>Вообще говоря это не так.
А как?
S>Но в вашем случае WriteTransformation просто продолжит нагнетать пургу. Если вашего пользователя устроит такой подход, то мне нет больше до этого дела.
Что значи нагнетать пургу? Если данные переданы неправильно, то пользователь в любом случае не получит правильного ответа и он об этом будет знать.
S>>>Вашь пользователь работает с WriteTransformation напрямую?
AN>>Конечно нет, но эта функция отностися к блоку не имеющему права выдавать исключения.
S>Ваш блок даже не выдает код ошибки, а просто гонит. Печально то, что об этом может никто не узнать и считать что блок отрабатывает верно.
А у него такая задача не прерывать цепочку, чтобы не случилось.

AN>>>>Просто как более понятный пример

S>>>Вы его неверно трактуете.
AN>>Тут вопрос кто его неправильно трактует. Возможно мы его понимает по разному.
S>Вы его понимаете так, будто приложение должно делать то для чего оно написано, даже если данные повреждены.
А что бы вы предложили?
S>>>Если все методы приложения будут гнать пургу в ответ на пургу во входных данных, ваше приложение просто будет молча делать пургу вместо того что ожидает пользователь.
AN>>никто не ведет речь о всех методах, есть просто различные части с различным "поведением".
S>"поведение" вашего блока — нагнетать пургу и делать вид что все ок.
В данном случае задача формулируется так: если регулировщика переехала машина перекресток должен остаться регулируемым, пусть даже и строго в одном направлении.
Вполне возможно, что кто то может сказать блин — это ведь негуманно, давайте остановим движение и спасем регулировщика.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[19]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 12:45
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


AN>И при этом я не хочу утверждать что мое правильное или Ваше нет.

Я тоже ничего не утвреждаю по поводу правильности мнений. Делюсь своим. Не нужно — только намекните.

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

AN>>>показ диалога сообщения об ошибке и аврийное прерывания текущей операции.
S>>Вообще говоря это не так.
AN>А как?
Исключения бывают ожидаемыми и обрабатываемыми. Недостаточно данных для работы — нужно сказать пользователю что их недостаточно для работы. Не обязательно при этом делать вид что все работает, или показывать диалог с аварийным завершением.

AN>Что значи нагнетать пургу? Если данные переданы неправильно, то пользователь в любом случае не получит правильного ответа и он об этом будет знать.

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

S>>Ваш блок даже не выдает код ошибки, а просто гонит. Печально то, что об этом может никто не узнать и считать что блок отрабатывает верно.

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

AN>>>>>Просто как более понятный пример

S>>>>Вы его неверно трактуете.
AN>>>Тут вопрос кто его неправильно трактует. Возможно мы его понимает по разному.
S>>Вы его понимаете так, будто приложение должно делать то для чего оно написано, даже если данные повреждены.
AN>А что бы вы предложили?
fail fast. В этом случае вы хотя бы узнаете, что нечто пошло не так и сможете сказать об этом пользователю, он обратится к вам и вы позже исправите ситуацию.

S>>"поведение" вашего блока — нагнетать пургу и делать вид что все ок.

AN>В данном случае задача формулируется так: если регулировщика переехала машина перекресток должен остаться регулируемым, пусть даже и строго в одном направлении.
Он не будет регулируемым, он будет регулируемым хаотически

AN>Вполне возможно, что кто то может сказать блин — это ведь негуманно, давайте остановим движение и спасем регулировщика.

В вашем случае никто не узнает что что-то произошло и все будут делать вид что так и должно быть.
Re[20]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 13:22
Оценка:
Здравствуйте, samius, Вы писали:

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


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


AN>>И при этом я не хочу утверждать что мое правильное или Ваше нет.

S>Я тоже ничего не утвреждаю по поводу правильности мнений. Делюсь своим. Не нужно — только намекните.
Ну почему, из любой дискуссии можно вынести что то полезное.

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

AN>>>>показ диалога сообщения об ошибке и аврийное прерывания текущей операции.
S>>>Вообще говоря это не так.
AN>>А как?
S>Исключения бывают ожидаемыми и обрабатываемыми. Недостаточно данных для работы — нужно сказать пользователю что их недостаточно для работы. Не обязательно при этом делать вид что все работает, или показывать диалог с аварийным завершением.
То бишь функцию лучше обвернуть в тру/сатч который нифига не делает?

AN>>Что значи нагнетать пургу? Если данные переданы неправильно, то пользователь в любом случае не получит правильного ответа и он об этом будет знать.

S>Вы предлагаете ему самому догадаться что в неком блоке с запретом на исключения в метод WriteTransformation пришли неправильные данные и в итоге он получил не то что хотел? А вдруг, то что он увидит в результате он примет за верный результат? У вас даже программа не знает о том что что-то пошло не так. Так откуда пользователь об этом будет знать?
Любой "пользователь" об этом узнает.
Если расматривать реального пользователя, то он оправляет некую команду на выполнение, а в результате получает сообщение, что команда выполнилась неправильно (так как ожидаемые данные не были получены). Если расмматривать пользователя- приемника информации, то он получает даже больше чем нужно. Он получает всего лишь один байт, что невозможно. Поэтому он знает что была просто неверная передача, а не то что клиент свалил.

S>>>Ваш блок даже не выдает код ошибки, а просто гонит. Печально то, что об этом может никто не узнать и считать что блок отрабатывает верно.

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

AN>>>>>>Просто как более понятный пример

S>>>>>Вы его неверно трактуете.
AN>>>>Тут вопрос кто его неправильно трактует. Возможно мы его понимает по разному.
S>>>Вы его понимаете так, будто приложение должно делать то для чего оно написано, даже если данные повреждены.
AN>>А что бы вы предложили?
S>fail fast. В этом случае вы хотя бы узнаете, что нечто пошло не так и сможете сказать об этом пользователю, он обратится к вам и вы позже исправите ситуацию.
Как раз это и не требуется.
S>>>"поведение" вашего блока — нагнетать пургу и делать вид что все ок.
AN>>В данном случае задача формулируется так: если регулировщика переехала машина перекресток должен остаться регулируемым, пусть даже и строго в одном направлении.
S>Он не будет регулируемым, он будет регулируемым хаотически
Отчего? Данные или будут проходит правильные или нет.
AN>>Вполне возможно, что кто то может сказать блин — это ведь негуманно, давайте остановим движение и спасем регулировщика.
S>В вашем случае никто не узнает что что-то произошло и все будут делать вид что так и должно быть.
Именно в нашем случае это будет известно так как ожидаемые данные не получены.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[20]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 13:29
Оценка:
Здравствуйте, hardcase, Вы писали:

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


S>>>Ваш блок даже не выдает код ошибки, а просто гонит. Печально то, что об этом может никто не узнать и считать что блок отрабатывает верно.

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

H>Запет на выброс исключений это совсем не картбланш на GI/GO (Garbage In — Garbage Out). Корректность входных данных проверять всеравно необходимо, и функция, которая не использует исключения для сигнализации, данных должна возвращать код результата (ошибки).

Чем возвращать код ошибки так уж лучше генерить исключение.
Это все весьма замечательно в теории, и я бы видимо тоже горячо об этом спорил.
Но что мне нужно делать при ошибке — не идти дальше. А вот это и заключается проблема что нужно пойти дальше не отклоняясь от пути.
Если красной шапочке не дали пирожков ей надо все равно идти, а не кричать где мои пирожки, иначе у бабушки будет инфаркт, от того что шапочка не пришла вовремя
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[21]: Как не надо писать код
От: hardcase Пират http://nemerle.org
Дата: 22.04.11 13:32
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Чем возвращать код ошибки так уж лучше генерить исключение.

AN>Это все весьма замечательно в теории, и я бы видимо тоже горячо об этом спорил.

WinAPI как-то ведь работает? А там нет исключений — сплошные коды возвратов.

AN>Но что мне нужно делать при ошибке — не идти дальше. А вот это и заключается проблема что нужно пойти дальше не отклоняясь от пути.


А вот это должен решать код, который вызывает функцию. Т.е. обрабатывать код возврата.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[22]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 13:49
Оценка:
Здравствуйте, hardcase, Вы писали:

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


AN>>Чем возвращать код ошибки так уж лучше генерить исключение.

AN>>Это все весьма замечательно в теории, и я бы видимо тоже горячо об этом спорил.

H>WinAPI как-то ведь работает? А там нет исключений — сплошные коды возвратов.

Я вообще то немного другое имел в виду.
Но можно пойти и по этому пути. А нафига тогда сделали исключения если и с кодом возврата было все так замечательно?

AN>>Но что мне нужно делать при ошибке — не идти дальше. А вот это и заключается проблема что нужно пойти дальше не отклоняясь от пути.


H>А вот это должен решать код, который вызывает функцию. Т.е. обрабатывать код возврата.

Иначе говоря всегда игнорировать код возврата. А потом, еще, в случае ошибки генерировать "нулевые данные" и идти дальше? Если бы фукнция входила в состав библиотеки для общего применения возможно именно так и поступили.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[21]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 14:14
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


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

AN>То бишь функцию лучше обвернуть в тру/сатч который нифига не делает?
Это еще хуже, чем у вас сейчас. И я такого не предлагал.

AN>Любой "пользователь" об этом узнает.

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

S>>fail fast. В этом случае вы хотя бы узнаете, что нечто пошло не так и сможете сказать об этом пользователю, он обратится к вам и вы позже исправите ситуацию.

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

S>>Он не будет регулируемым, он будет регулируемым хаотически

AN>Отчего? Данные или будут проходит правильные или нет.
Нет, они будут приходить либо правдоподобные либо нет. Гарантировать корректность правдоподобных данных никто не будет.

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

AN>Именно в нашем случае это будет известно так как ожидаемые данные не получены.
Почему? Вы их получите, но не будете знать, то ли это, что хотели отправить.
Re[23]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 14:19
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Но можно пойти и по этому пути. А нафига тогда сделали исключения если и с кодом возврата было все так замечательно?

Нафига: что бы не анализировать коды возврата после каждого вызова

H>>А вот это должен решать код, который вызывает функцию. Т.е. обрабатывать код возврата.

AN>Иначе говоря всегда игнорировать код возврата. А потом, еще, в случае ошибки генерировать "нулевые данные" и идти дальше? Если бы фукнция входила в состав библиотеки для общего применения возможно именно так и поступили.
"нулевые данные" это уже какая-то гарантия что не будут отправлены ошибочные данные.
Re[24]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 15:18
Оценка:
Здравствуйте, samius, Вы писали:

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


AN>>Но можно пойти и по этому пути. А нафига тогда сделали исключения если и с кодом возврата было все так замечательно?

S>Нафига: что бы не анализировать коды возврата после каждого вызова
Думаю что не только, но думаю вы также согласны что исключение немного получше чем код возрата.

H>>>А вот это должен решать код, который вызывает функцию. Т.е. обрабатывать код возврата.

AN>>Иначе говоря всегда игнорировать код возврата. А потом, еще, в случае ошибки генерировать "нулевые данные" и идти дальше? Если бы фукнция входила в состав библиотеки для общего применения возможно именно так и поступили.
S>"нулевые данные" это уже какая-то гарантия что не будут отправлены ошибочные данные.
А что по вашему делает тогда функция, как не геренерит "нулевые данные" по ошибке.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[22]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 15:24
Оценка:
Здравствуйте, samius, Вы писали:

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


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


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

AN>>То бишь функцию лучше обвернуть в тру/сатч который нифига не делает?
S>Это еще хуже, чем у вас сейчас. И я такого не предлагал.
А что вы предлагаете?

AN>>Любой "пользователь" об этом узнает.

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

S>>>fail fast. В этом случае вы хотя бы узнаете, что нечто пошло не так и сможете сказать об этом пользователю, он обратится к вам и вы позже исправите ситуацию.

AN>>Как раз это и не требуется.
S>На моей старой работе была ситуация, когда программа готовилась на выставку, и там надо было гарантировать что никто не узнает, что программа не работает как это от нее ждут
В данном случае ситуация несколько другая. При неверных данных входные данных надо выдавать так называеты "нулевые данные", что в принципе и является кодом ошибки.

S>>>Он не будет регулируемым, он будет регулируемым хаотически

AN>>Отчего? Данные или будут проходит правильные или нет.
S>Нет, они будут приходить либо правдоподобные либо нет. Гарантировать корректность правдоподобных данных никто не будет.
В любом случае мы имеет три детерминированные ситуации:
— на входе правильные данные, на выходе правильные
— на входе правильные данные, на выходе "нулевые"
— на входе неправильные данные, на выходе "нулевые"
где проблема?

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

AN>>Именно в нашем случае это будет известно так как ожидаемые данные не получены.
S>Почему? Вы их получите, но не будете знать, то ли это, что хотели отправить.
А пому мы их получим, если команда на отправку не получена. Если даже что то и прийдет, то это должно быть не что то, а конкретный ответ на конкретную коамнду.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[25]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 15:30
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


S>>Нафига: что бы не анализировать коды возврата после каждого вызова

AN>Думаю что не только, но думаю вы также согласны что исключение немного получше чем код возрата.
Не согласен. В разных случаях по разному. Но глотать проблему — совершенно точно не выход.

S>>"нулевые данные" это уже какая-то гарантия что не будут отправлены ошибочные данные.

AN>А что по вашему делает тогда функция, как не геренерит "нулевые данные" по ошибке.
Версия Sinclair-а кидается исключениями. Ваша — глотает ошибку. Ну или покажите мне, где эта генерация "нулевых данных".
Re[23]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 15:39
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


S>>Это еще хуже, чем у вас сейчас. И я такого не предлагал.

AN>А что вы предлагаете?
Предлагаю не замалчивать проблему.

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

AN>Кто сказал, что такой подход используется повсеместно?
Я проэкстраполировал ваше отношение к исключениям вместе с примерами распознавания. Уверен, что не ошибся.

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

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

AN>В любом случае мы имеет три детерминированные ситуации:

AN>- на входе правильные данные, на выходе правильные
AN>- на входе правильные данные, на выходе "нулевые"
AN>- на входе неправильные данные, на выходе "нулевые"
AN>где проблема?
Проблема в том что нет кода, отличающего правильные от неправильных. Ваш передает любые данные после некоторой модификации.

S>>Почему? Вы их получите, но не будете знать, то ли это, что хотели отправить.

AN>А пому мы их получим, если команда на отправку не получена. Если даже что то и прийдет, то это должно быть не что то, а конкретный ответ на конкретную коамнду.
Конкретный искаженный ошибкой ответ на конкретную искаженную ошибкой команду. Вы уверены, что это то чего вы ожидаете от программы? Откуда будет уверенность что получили ответ на то что посылали вообще?
Re[26]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 15:47
Оценка:
Здравствуйте, samius, Вы писали:

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


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


S>>>Нафига: что бы не анализировать коды возврата после каждого вызова

AN>>Думаю что не только, но думаю вы также согласны что исключение немного получше чем код возрата.
S>Не согласен. В разных случаях по разному. Но глотать проблему — совершенно точно не выход.
Для чего нужны разные случаи, почему нельзя все сделлать единообразно?
S>>>"нулевые данные" это уже какая-то гарантия что не будут отправлены ошибочные данные.
AN>>А что по вашему делает тогда функция, как не геренерит "нулевые данные" по ошибке.
S>Версия Sinclair-а кидается исключениями. Ваша — глотает ошибку. Ну или покажите мне, где эта генерация "нулевых данных".
Не имею понятия как это показать.
Но буфер должен быть либо нуль, либо содержать только префикс
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[24]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 15:58
Оценка:
Здравствуйте, samius, Вы писали:

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


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


S>>>Это еще хуже, чем у вас сейчас. И я такого не предлагал.

AN>>А что вы предлагаете?
S>Предлагаю не замалчивать проблему.
Ок, кричим, что дальше?

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

AN>>Кто сказал, что такой подход используется повсеместно?
S>Я проэкстраполировал ваше отношение к исключениям вместе с примерами распознавания. Уверен, что не ошибся.
Блин, прийдется убирать модуль обработки ошибок

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

S>Т.е. вместо того чтобы кто-то анализировал код ошибки, он должен разобрать данные и понять что они неверные? Но эти данные ведь не возвращаются вызывающему коду!
Я же говорил о цепочке. Цепочка или вся работает или нет. Модуль стоящий в начале цепочки спокойно все и определяет

AN>>В любом случае мы имеет три детерминированные ситуации:

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

S>>>Почему? Вы их получите, но не будете знать, то ли это, что хотели отправить.

AN>>А пому мы их получим, если команда на отправку не получена. Если даже что то и прийдет, то это должно быть не что то, а конкретный ответ на конкретную коамнду.
S>Конкретный искаженный ошибкой ответ на конкретную искаженную ошибкой команду. Вы уверены, что это то чего вы ожидаете от программы? Откуда будет уверенность что получили ответ на то что посылали вообще?>
То есть две ошибки сразу?
Команда не может исказится в данном методе. По крайней мере, я не вижу этого.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[27]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 17:11
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


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


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


S>>>>Нафига: что бы не анализировать коды возврата после каждого вызова

AN>>>Думаю что не только, но думаю вы также согласны что исключение немного получше чем код возрата.
S>>Не согласен. В разных случаях по разному. Но глотать проблему — совершенно точно не выход.
AN>Для чего нужны разные случаи, почему нельзя все сделлать единообразно?
Разные случаи не нужны, они есть. В них либо может быть ситуация не исключительная, тогда код возврата.
Dictionary.TryGetValue — отсутствие ключа — исключительная ситуация, отсутствие записи — штатная с кодом возврата.
В других исключений избегают по соображениям производительности.

S>>>>"нулевые данные" это уже какая-то гарантия что не будут отправлены ошибочные данные.

AN>>>А что по вашему делает тогда функция, как не геренерит "нулевые данные" по ошибке.
S>>Версия Sinclair-а кидается исключениями. Ваша — глотает ошибку. Ну или покажите мне, где эта генерация "нулевых данных".
AN>Не имею понятия как это показать.
AN>Но буфер должен быть либо нуль, либо содержать только префикс
В оригинальном коде никакого анализа нет на эту тему. Приходят рассогласованные данные на вход и результат сложно предсказать.
Re[26]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 17:23
Оценка:
Здравствуйте, samius, Вы писали:

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


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


S>>>Предлагаю не замалчивать проблему.

AN>>Ок, кричим, что дальше?
S>реагируем
Каким образом?
Скажем так, ранее этой функции не было и не планировалось. Потом понадобилась, соотвественно ничего нарушать она не должна.

AN>>>>Кто сказал, что такой подход используется повсеместно?

S>>>Я проэкстраполировал ваше отношение к исключениям вместе с примерами распознавания. Уверен, что не ошибся.
AN>>Блин, прийдется убирать модуль обработки ошибок
S>Занятно! Т.е. у вас есть модули которые ошибки прячут, и есть которые их спрятанные обрабатывают?
Есть разные типы модулей, вроде уже писал какие.

AN>>Я же говорил о цепочке. Цепочка или вся работает или нет. Модуль стоящий в начале цепочки спокойно все и определяет

S>Он даже не может определить, ушли ли от него верные данные
А это ему и нахрен не надо, да это и физически невозможно. Данные передаются через канал который ну просто невозможно контролировать и наличие ошибок в нем гораздо белее вероятно.
Если я говорю человеку скажи А, а он говорит Б или молчит это достаточно чтобы считать цепочку невыполненной, отчего это произошло не интересует.
AN>>его задача просто ретранслировать данные если он не может этого сделать генерируются "нулевые данные"
S>По-моему пора завязывать.
Как есть желание.
S>>>Конкретный искаженный ошибкой ответ на конкретную искаженную ошибкой команду. Вы уверены, что это то чего вы ожидаете от программы? Откуда будет уверенность что получили ответ на то что посылали вообще?>
AN>>То есть две ошибки сразу?
AN>>Команда не может исказится в данном методе. По крайней мере, я не вижу этого.
S>Вы исходите из того что весь код написан верно. Это работает только в том случае, если весь код написан верно. Если что-то неверно, то ошибка размазывается по всей цепочке, т.е. никаких данных о том, на каком этапе возникла ошибка у вас нет. Есть только "нулевые" данные на выходе.
Как раз наоборот, предполагается что все неверно.
S>В общем, успехов в отладке!
Понимаю Вашу иронию, но не все так плохо как вам кажется.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[28]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 17:30
Оценка:
Здравствуйте, samius, Вы писали:

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


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


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


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


S>>>>>Нафига: что бы не анализировать коды возврата после каждого вызова

AN>>>>Думаю что не только, но думаю вы также согласны что исключение немного получше чем код возрата.
S>>>Не согласен. В разных случаях по разному. Но глотать проблему — совершенно точно не выход.
AN>>Для чего нужны разные случаи, почему нельзя все сделлать единообразно?
S>Разные случаи не нужны, они есть. В них либо может быть ситуация не исключительная, тогда код возврата.
S>Dictionary.TryGetValue — отсутствие ключа — исключительная ситуация, отсутствие записи — штатная с кодом возврата.
S>В других исключений избегают по соображениям производительности.
Если имеется в виду это
 value
    Type: TValue
When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.


То именно так и делается

S>>>>>"нулевые данные" это уже какая-то гарантия что не будут отправлены ошибочные данные.

AN>>>>А что по вашему делает тогда функция, как не геренерит "нулевые данные" по ошибке.
S>>>Версия Sinclair-а кидается исключениями. Ваша — глотает ошибку. Ну или покажите мне, где эта генерация "нулевых данных".
AN>>Не имею понятия как это показать.
AN>>Но буфер должен быть либо нуль, либо содержать только префикс
S>В оригинальном коде никакого анализа нет на эту тему. Приходят рассогласованные данные на вход и результат сложно предсказать.
Результат сложно предсказать потому, что код хреново написан, именно поэтому и тему сделал. Смотришь в код и нифига не видишь
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[27]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 17:30
Оценка:
Здравствуйте, AlexNek, Вы писали:

S>>реагируем

AN>Каким образом?
Fail Fast!
AN>Скажем так, ранее этой функции не было и не планировалось. Потом понадобилась, соотвественно ничего нарушать она не должна.
Если она понадобилась, значит что-то она должна делать и делать это корректно. Если это не так, то лучше ее выкинуть нафик.

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

Добавьте к нему свои ошибки

S>>По-моему пора завязывать.

AN>Как есть желание.
Есть желание завязывать

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

AN>Как раз наоборот, предполагается что все неверно.

S>>В общем, успехов в отладке!

AN>Понимаю Вашу иронию, но не все так плохо как вам кажется.
Re[29]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 17:36
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


S>>Dictionary.TryGetValue — отсутствие ключа — исключительная ситуация, отсутствие записи — штатная с кодом возврата.

S>>В других исключений избегают по соображениям производительности.
AN>Если имеется в виду это
AN>
AN> value
AN>    Type: TValue

AN>
When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.


AN>То именно так и делается

Нет. В случае TryGetValue у вызывающего кода есть возможность узнать что
а) данные переданы корректно
б) указанный ключ зарегистрирован (или нет)

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

AN>Результат сложно предсказать потому, что код хреново написан, именно поэтому и тему сделал. Смотришь в код и нифига не видишь

Это я заметил. Так же как и то, что к вызываемому коду не предъявляется никаких требований. А значит вызывать этот метод могут как угодно.
Re[28]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 17:41
Оценка:
Здравствуйте, samius, Вы писали:

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


S>>>реагируем

AN>>Каким образом?
S>Fail Fast!
Тогда приходим к примеру с OCR
AN>>Скажем так, ранее этой функции не было и не планировалось. Потом понадобилась, соотвественно ничего нарушать она не должна.
S>Если она понадобилась, значит что-то она должна делать и делать это корректно. Если это не так, то лучше ее выкинуть нафик.
Так она и делает это корректно.

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

S>Добавьте к нему свои ошибки
Да хоть ведро, при наличии ошибок не будет нужного ответа.

S>>>По-моему пора завязывать.

AN>>Как есть желание.
S>Есть желание завязывать
Тогда приятного вечера, хороших выходных и большое спасибо
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[30]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 17:53
Оценка:
Здравствуйте, samius, Вы писали:

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


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


S>>>Dictionary.TryGetValue — отсутствие ключа — исключительная ситуация, отсутствие записи — штатная с кодом возврата.

S>>>В других исключений избегают по соображениям производительности.
AN>>Если имеется в виду это
AN>>
AN>> value
AN>>    Type: TValue

AN>>
When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the value parameter. This parameter is passed uninitialized.


AN>>То именно так и делается

S>Нет. В случае TryGetValue у вызывающего кода есть возможность узнать что
S>а) данные переданы корректно
Куда переданны?
S>б) указанный ключ зарегистрирован (или нет)

S>В вашем случае вызывающий код не знает ничего о том, правильно ли он подал данные. положит он 10000 в bufferLength и для него ничего не изменится.

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

AN>>Результат сложно предсказать потому, что код хреново написан, именно поэтому и тему сделал. Смотришь в код и нифига не видишь

S>Это я заметил. Так же как и то, что к вызываемому коду не предъявляется никаких требований. А значит вызывать этот метод могут как угодно.
Требования есть (не давать непраыильных данных ), но считается, что вызывающий код способен на любую подлость.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[29]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 18:27
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


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


S>>Fail Fast!

AN>Тогда приходим к примеру с OCR
отвечу в следующем сообщении

S>>Есть желание завязывать

AN>Тогда приятного вечера, хороших выходных и большое спасибо
Принимаю
Re[31]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 22.04.11 18:37
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


S>>Нет. В случае TryGetValue у вызывающего кода есть возможность узнать что

S>>а) данные переданы корректно
AN>Куда переданны?
В метод TryGetValue
S>>б) указанный ключ зарегистрирован (или нет)

К вопросу об OCR. Вы обсжуждаете вариант, при котором в данных не может быть распознан некий символ. Я обсуждаю вариант, при котором данные не пригодны для анализа. Вернемся к tryGetValue:
а) то что не выскочило исключение из этого метода говорит о том, что данные ему переданы корректно, что там не null!
б) код возврата говорит о том, нашлась запись по ключу или нет.
В вашем случае ничего не говорит ни о том ни о другом.

AN>А ему это и не требуется знать. Задача модуля выстоять до последенего патрона. А не докладывать обстановку наверх после каждого вражеского выстрела.

В данном случае он будет стрелять по своим

S>>Это я заметил. Так же как и то, что к вызываемому коду не предъявляется никаких требований. А значит вызывать этот метод могут как угодно.

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

Представьте, что TryGetValue возвращает true если ему передали null в качестве ключа. Будет ли это гуманно?
Re[32]: Как не надо писать код
От: AlexNek  
Дата: 22.04.11 20:11
Оценка:
Здравствуйте, samius, Вы писали:

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


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


S>>>Нет. В случае TryGetValue у вызывающего кода есть возможность узнать что

S>>>а) данные переданы корректно
AN>>Куда переданны?
S>В метод TryGetValue
S>>>б) указанный ключ зарегистрирован (или нет)

S>К вопросу об OCR. Вы обсжуждаете вариант, при котором в данных не может быть распознан некий символ. Я обсуждаю вариант, при котором данные не пригодны для анализа.

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

S>Вернемся к tryGetValue:

S>а) то что не выскочило исключение из этого метода говорит о том, что данные ему переданы корректно, что там не null!
S>б) код возврата говорит о том, нашлась запись по ключу или нет.
А где там есть код возврата? Это задача функции сказать есть там данные или нет.
S>В вашем случае ничего не говорит ни о том ни о другом.
А это от нее и не требуется. Функция не является методом "спросил ответил". Есть некий поток данных и она просто вклинивается внутрь. Метод уже передал данные дальше, что будет с ними дальше его уже не волнует. Но если он выдает ошибочные данные их весьма нежелательно передавать дальше. Поэтому у этой функции как бы два "официальных" задания: преобразовать данные, в случае невозможности преобразования выдать "нулевые данные". Согласен, что нехорошо давать одной функции два задания, но иначе интерфейс был бы слишком запутанный.

AN>>А ему это и не требуется знать. Задача модуля выстоять до последенего патрона. А не докладывать обстановку наверх после каждого вражеского выстрела.

S>В данном случае он будет стрелять по своим
Не будет, уже проверяли

S>>>Это я заметил. Так же как и то, что к вызываемому коду не предъявляется никаких требований. А значит вызывать этот метод могут как угодно.

AN>>Требования есть (не давать непраыильных данных ), но считается, что вызывающий код способен на любую подлость.
S>Подлость — это вызываемому коду не отвечать на другую подлость.
А ему такое задание дали улаживать конфликты.

S>Представьте, что TryGetValue возвращает true если ему передали null в качестве ключа. Будет ли это гуманно?

Это меняеет описание поведения функции. null можно рассматривать как эквивалент всегда неверного ключа, так как null в качестве ключа не разрешен, поэтому возврат false был бы более гуманным методом.
... << RSDN@Home 1.2.0 alpha 5-AN rev. 351>>
Re[33]: Как не надо писать код
От: hardcase Пират http://nemerle.org
Дата: 22.04.11 20:34
Оценка:
Здравствуйте, AlexNek, Вы писали:

S>>К вопросу об OCR. Вы обсжуждаете вариант, при котором в данных не может быть распознан некий символ. Я обсуждаю вариант, при котором данные не пригодны для анализа.

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

Неправильно понимаете. Обработка исключения и будет сводиться к показу пустой страницы с текстом, что невозможно проанализировать данные.
/* иЗвиНите зА неРовнЫй поЧерК */
Re[34]: Как не надо писать код
От: AlexNek  
Дата: 23.04.11 08:31
Оценка:
Здравствуйте, hardcase, Вы писали:

h> S>>К вопросу об OCR. Вы обсжуждаете вариант, при котором в данных не может быть распознан некий символ. Я обсуждаю вариант, при котором данные не пригодны для анализа.


h> AN>В этом случае также ничего не надо делать, а показать пустую страницу, с текстом что невозможно проанализировать данные.

h> AN>В случае исключения надо было не показывать страницу вообще, а выдать сообщение об ошибке.

h> Неправильно понимаете. Обработка исключения и будет сводиться к показу пустой страницы с текстом, что невозможно проанализировать данные.

Логика получается слишком сложная, которую сложно развивать. Не говоря о том что модуль отображения находится в километре от приема. Если исключения возникают в модуле приема "по внутренним причинам", то в этом случае страница, не показывается — это ошибка модуля ее нужно показать и обработать как ошибку. Если же просто ошибка приема данных, то тут показываем страницу с пометкой.
(Хотя пожалуй, можно сделать базовый класс для ошибок приема)
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[33]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 24.04.11 19:12
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


S>>К вопросу об OCR. Вы обсжуждаете вариант, при котором в данных не может быть распознан некий символ. Я обсуждаю вариант, при котором данные не пригодны для анализа.

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

S>>Вернемся к tryGetValue:

S>>а) то что не выскочило исключение из этого метода говорит о том, что данные ему переданы корректно, что там не null!
S>>б) код возврата говорит о том, нашлась запись по ключу или нет.
AN>А где там есть код возврата? Это задача функции сказать есть там данные или нет.
Не путайте с ContainsKey. Задача TryGetValue — достать значение. Возвращенный bool — это код возврата.

S>>В вашем случае ничего не говорит ни о том ни о другом.

AN>А это от нее и не требуется. Функция не является методом "спросил ответил". Есть некий поток данных и она просто вклинивается внутрь. Метод уже передал данные дальше, что будет с ними дальше его уже не волнует. Но если он выдает ошибочные данные их весьма нежелательно передавать дальше. Поэтому у этой функции как бы два "официальных" задания: преобразовать данные, в случае невозможности преобразования выдать "нулевые данные". Согласен, что нехорошо давать одной функции два задания, но иначе интерфейс был бы слишком запутанный.
Эта техника способствует сокрытию ошибок вместо их исправления

AN>>>А ему это и не требуется знать. Задача модуля выстоять до последенего патрона. А не докладывать обстановку наверх после каждого вражеского выстрела.

S>>В данном случае он будет стрелять по своим
AN>Не будет, уже проверяли
Откуда такая уверенность? Ваша программа больше не модифицируется?

S>>Подлость — это вызываемому коду не отвечать на другую подлость.

AN>А ему такое задание дали улаживать конфликты.
Он их не улаживает, он их заметает под ковер

S>>Представьте, что TryGetValue возвращает true если ему передали null в качестве ключа. Будет ли это гуманно?

AN>Это меняеет описание поведения функции. null можно рассматривать как эквивалент всегда неверного ключа, так как null в качестве ключа не разрешен, поэтому возврат false был бы более гуманным методом.
На самом деле столь же гуманным как и true, потому как у вызывающего кода нет возможности понять, как именно трактовать результат, как признак нарушения контракта, либо как признак наличия/отсутствия данных. Что бы разобраться с этим вопросом на стороне вызывающего кода, придется продублировать проверку данных и следить что бы она совпадала с той, что на стороне вызываемого кода.
Re[34]: Как не надо писать код
От: AlexNek  
Дата: 25.04.11 11:34
Оценка:
Здравствуйте, samius, Вы писали:

s> S>>К вопросу об OCR. Вы обсжуждаете вариант, при котором в данных не может быть распознан некий символ. Я обсуждаю вариант, при котором данные не пригодны для анализа.


s> AN>В этом случае также ничего не надо делать, а показать пустую страницу, с текстом что невозможно проанализировать данные.


s> И что мешает?

система обработки ошибок
s> AN>В случае исключения надо было не показывать страницу вообще, а выдать сообщение об ошибке.

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

Так именно об этом я и говорю. Нужно иметь отличие ошибки и ошибочной ситуации.
s> S>>Вернемся к tryGetValue:
s> S>>а) то что не выскочило исключение из этого метода говорит о том, что данные ему переданы корректно, что там не null!
s> S>>б) код возврата говорит о том, нашлась запись по ключу или нет.

s> AN>А где там есть код возврата? Это задача функции сказать есть там данные или нет.


s> Не путайте с ContainsKey. Задача TryGetValue — достать значение. Возвращенный bool — это код возврата.

Странно, говорят немного о другом
Return Value
Type: System.Boolean
true if the Dictionary<TKey, TValue> contains an element with the specified key; otherwise, false.

s> S>>В вашем случае ничего не говорит ни о том ни о другом.

s> AN>А это от нее и не требуется. Функция не является методом "спросил ответил". Есть некий поток данных и она просто вклинивается внутрь. Метод уже передал данные дальше, что будет с ними дальше его уже не волнует. Но если он выдает ошибочные данные их весьма нежелательно передавать дальше. Поэтому у этой функции как бы два "официальных" задания: преобразовать данные, в случае невозможности преобразования выдать "нулевые данные". Согласен, что нехорошо давать одной функции два задания, но иначе интерфейс был бы слишком запутанный.


s> Эта техника способствует сокрытию ошибок вместо их исправления

Не призываю применять ее повсеместно и не утверждаю что это хорошо.

s> AN>>>А ему это и не требуется знать. Задача модуля выстоять до последенего патрона. А не докладывать обстановку наверх после каждого вражеского выстрела.


s> S>>В данном случае он будет стрелять по своим


s> AN>Не будет, уже проверяли


s> Откуда такая уверенность? Ваша программа больше не модифицируется?

Данный модуль не планируется никак модифицировать.

s> S>>Подлость — это вызываемому коду не отвечать на другую подлость.


s> AN>А ему такое задание дали улаживать конфликты.


s> Он их не улаживает, он их заметает под ковер


s> S>>Представьте, что TryGetValue возвращает true если ему передали null в качестве ключа. Будет ли это гуманно?


s> AN>Это меняеет описание поведения функции. null можно рассматривать как эквивалент всегда неверного ключа, так как null в качестве ключа не разрешен, поэтому возврат false был бы более гуманным методом.


s> На самом деле столь же гуманным как и true, потому как у вызывающего кода нет возможности понять, как именно трактовать результат, как признак нарушения контракта, либо как признак наличия/отсутствия данных. Что бы разобраться с этим вопросом на стороне вызывающего кода, придется продублировать проверку данных и следить что бы она совпадала с той, что на стороне вызываемого кода.

Тут нужно спросить а надо ли нам трактовать результат?
Давайте попросим код ошибки от Console.WriteLine и будем извещать пользователя если что не так
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[35]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.04.11 12:04
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> И что мешает?

AN>система обработки ошибок
Что-то не так с вашей системой

AN>Так именно об этом я и говорю. Нужно иметь отличие ошибки и ошибочной ситуации.

Дык у вас и то и другое ничем не отличается от нормы

s>> Не путайте с ContainsKey. Задача TryGetValue — достать значение. Возвращенный bool — это код возврата.

AN>Странно, говорят немного о другом
AN>
Return Value
AN>Type: System.Boolean
AN>true if the Dictionary<TKey, TValue> contains an element with the specified key; otherwise, false.
AN>

О чем о другом? О том что нужно использовать TryGetValue вместо ContainsKey, или о том что возвращаемое значение не является кодом возврата? Я ничего такого не вижу.

s>> Откуда такая уверенность? Ваша программа больше не модифицируется?

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

s>> На самом деле столь же гуманным как и true, потому как у вызывающего кода нет возможности понять, как именно трактовать результат, как признак нарушения контракта, либо как признак наличия/отсутствия данных. Что бы разобраться с этим вопросом на стороне вызывающего кода, придется продублировать проверку данных и следить что бы она совпадала с той, что на стороне вызываемого кода.

AN>Тут нужно спросить а надо ли нам трактовать результат?
Я уже понял, что вам не надо. Именно против этого и выступаю.

AN>Давайте попросим код ошибки от Console.WriteLine и будем извещать пользователя если что не так

Будьте уверены, что если что не так, то из WriteLine вылетит исключение, которое даст знать, что именно не так. WriteLine как раз не будет делать вид что все "так".
Re[36]: Как не надо писать код
От: AlexNek  
Дата: 25.04.11 12:52
Оценка:
Здравствуйте, samius, Вы писали:

s> s>> И что мешает?


s> AN>система обработки ошибок


s> Что-то не так с вашей системой

Что именно?
Если она получает ошибку то для всех ошибок у нее есть стандартное действие, как миниму показать ошибку.

s> AN>Так именно об этом я и говорю. Нужно иметь отличие ошибки и ошибочной ситуации.


s> Дык у вас и то и другое ничем не отличается от нормы

откуда такая уверенность?

s> s>> Не путайте с ContainsKey. Задача TryGetValue — достать значение. Возвращенный bool — это код возврата.


s> AN>Странно, говорят немного о другом

s> AN>
Return Value
s> AN>Type: System.Boolean
s> AN>true if the Dictionary<TKey, TValue> contains an element with the specified key; otherwise, false.
s> AN>


s> О чем о другом? О том что нужно использовать TryGetValue вместо ContainsKey, или о том что возвращаемое значение не является кодом возврата? Я ничего такого не вижу.


что возвращаемое значение не является кодом возврата

s> s>> Откуда такая уверенность? Ваша программа больше не модифицируется?


s> AN>Данный модуль не планируется никак модифицировать.


s> Да же в случае если завтра в нем будет обнаружен баг?

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

s> s>> На самом деле столь же гуманным как и true, потому как у вызывающего кода нет возможности понять, как именно трактовать результат, как признак нарушения контракта, либо как признак наличия/отсутствия данных. Что бы разобраться с этим вопросом на стороне вызывающего кода, придется продублировать проверку данных и следить что бы она совпадала с той, что на стороне вызываемого кода.


s> AN>Тут нужно спросить а надо ли нам трактовать результат?


s> Я уже понял, что вам не надо. Именно против этого и выступаю.

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

s> AN>Давайте попросим код ошибки от Console.WriteLine и будем извещать пользователя если что не так


s> Будьте уверены, что если что не так, то из WriteLine вылетит исключение, которое даст знать, что именно не так. WriteLine как раз не будет делать вид что все "так".

А отчего микрософт не рекомендует его ловить, а делает так?
            try {
                billTotal = Double.Parse(args[0]);
            }
            catch(FormatException) {
                Console.WriteLine("usage: TIPCALC total");
                return 1;
            }
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[37]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 25.04.11 14:04
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> AN>система обработки ошибок


s>> Что-то не так с вашей системой

AN>Что именно?
AN>Если она получает ошибку то для всех ошибок у нее есть стандартное действие, как миниму показать ошибку.
То что она не предоставляет гибкость

s>> AN>Так именно об этом я и говорю. Нужно иметь отличие ошибки и ошибочной ситуации.


s>> Дык у вас и то и другое ничем не отличается от нормы

AN>откуда такая уверенность?
из вашего кода

s>> О чем о другом? О том что нужно использовать TryGetValue вместо ContainsKey, или о том что возвращаемое значение не является кодом возврата? Я ничего такого не вижу.


AN>что возвращаемое значение не является кодом возврата

Там такого не написано

s>> AN>Данный модуль не планируется никак модифицировать.

s>> Да же в случае если завтра в нем будет обнаружен баг?
AN>Вероятность довольно низкая, за несколько лет использования там практически не было исправлений.
И что будете делать при обнаружении бага или изменении требований? Считать вероятность или исправлять?

s>> Я уже понял, что вам не надо. Именно против этого и выступаю.

AN>Я только хочу сказать, что это не всегда нужно. Если бы функция была бы в библиотеке для прямого использования подписался бы под Вашими словами на все 100%.
Пусть не всегда. Но веские причины все-же не названы. Отсылка к OCR здесь ложная, т.к. ситуация другая.

s>> Будьте уверены, что если что не так, то из WriteLine вылетит исключение, которое даст знать, что именно не так. WriteLine как раз не будет делать вид что все "так".

AN>А отчего микрософт не рекомендует его ловить, а делает так?
Вопрос с подвохом. Покажите мне для начала то место где микрософт не рекомендует ловить исключения WriteLine.
Как считаете, для чего дан перечень исключений методов WriteLine, разве для того что бы их не ловили?
AN>
            try {
AN>                billTotal = Double.Parse(args[0]);
AN>            }
AN>            catch(FormatException) {
AN>                Console.WriteLine("usage: TIPCALC total");
AN>                return 1;
AN>            }
AN>

Показать вам код, который вышибет исключение из процитированного примера ровно в строчке WriteLine?
Re[38]: Как не надо писать код
От: AlexNek  
Дата: 25.04.11 16:00
Оценка:
Здравствуйте, samius, Вы писали:

s> s>> AN>система обработки ошибок


s> s>> Что-то не так с вашей системой


s> AN>Что именно?

s> AN>Если она получает ошибку то для всех ошибок у нее есть стандартное действие, как миниму показать ошибку.

s> То что она не предоставляет гибкость

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

s> s>> AN>Так именно об этом я и говорю. Нужно иметь отличие ошибки и ошибочной ситуации.


s> s>> Дык у вас и то и другое ничем не отличается от нормы


s> AN>откуда такая уверенность?


s> из вашего кода

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

s> s>> О чем о другом? О том что нужно использовать TryGetValue вместо ContainsKey, или о том что возвращаемое значение не является кодом возврата? Я ничего такого не вижу.


s> AN>что возвращаемое значение не является кодом возврата


s> Там такого не написано

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

s> s>> AN>Данный модуль не планируется никак модифицировать.


s> s>> Да же в случае если завтра в нем будет обнаружен баг?


s> AN>Вероятность довольно низкая, за несколько лет использования там практически не было исправлений.


s> И что будете делать при обнаружении бага или изменении требований? Считать вероятность или исправлять?

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

s> s>> Я уже понял, что вам не надо. Именно против этого и выступаю.


s> AN>Я только хочу сказать, что это не всегда нужно. Если бы функция была бы в библиотеке для прямого использования подписался бы под Вашими словами на все 100%.


s> Пусть не всегда. Но веские причины все-же не названы. Отсылка к OCR здесь ложная, т.к. ситуация другая.

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

s> s>> Будьте уверены, что если что не так, то из WriteLine вылетит исключение, которое даст знать, что именно не так. WriteLine как раз не будет делать вид что все "так".


s> AN>А отчего микрософт не рекомендует его ловить, а делает так?


s> Вопрос с подвохом. Покажите мне для начала то место где микрософт не рекомендует ловить исключения WriteLine.

Подобные вещи обычно находятся в коде, на такие мелочи они не размениваются.

s> Как считаете, для чего дан перечень исключений методов WriteLine, разве для того что бы их не ловили?

Ок давайте будем ловить. Понравилось?

            try {
                billTotal = Double.Parse(args[0]);
            }
            catch(FormatException) {
                try
                {
                    Console.WriteLine("usage: TIPCALC total");
                }
                catch (IOException ex)
                {
                    MessageBox.Show("Kirdyk 1");
                }
                return 1;
            }

            try
            {
               Console.WriteLine();
            }
            catch (IOException ex)
            {
                MessageBox.Show("Kirdyk 2");
            }

            try
            {
               Console.WriteLine("Bill total:\t{0,8:c}", billTotal);
            }
            catch (IOException ex)
            {
                MessageBox.Show("Kirdyk 3");
            }


s> Показать вам код, который вышибет исключение из процитированного примера ровно в строчке WriteLine?

И что даст это исключение для пользователя, в данном случае?
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[40]: Как не надо писать код
От: AlexNek  
Дата: 25.04.11 18:58
Оценка:
Здравствуйте, samius, Вы писали:

s> s>> То что она не предоставляет гибкость


s> AN>Тогда это будет уже совсем другая система, даже точнее не система а монстрик

s> AN>- она должна иметь множество путей обработки ошибок
s> AN>- она должна различать определенные ошибки и выбирать требуемый путь.
s> AN>- она должна знать что конкретно делать при каждом пути.
s> AN>- она должна располагаться на многих уровнях и иметь доступ к данным ее не касающихся.

s> Не знаю, что у вас за особенная система, но все перечисленное (кроме доступа к не касающимся данным) можно обеспечить грамотным использованием try/catch конструкций и глобальными обработчиками.

Ну это уже не система, а просто набор try/catch при этом нужен будет еще один определенный класс исключений "не обрабатывать" с указанием, что надо делать в этом случае.
s> s>> s>> Дык у вас и то и другое ничем не отличается от нормы

s> s>> AN>откуда такая уверенность?


s> s>> из вашего кода


s> AN>Во первых, код не мой, а во вторых это всего лишь маленькая часть.


s> Вижу, по выделенному возражений нет, кроме вопроса принадлежности кода?

Вы про "маленькую часть" еще забыли.

s> s>> AN>что возвращаемое значение не является кодом возврата


s> s>> Там такого не написано


s> AN>В противном случае там бы стояло, в случае ошибки.....

s> AN>И сравните описание возврата:
s> AN>-здесь
s> AN>-здесь

s> Походу вы собираетесь и дальше препираться на тему можно ли трактовать результат TryGetValue кодом возврата, вместо того что бы согласиться что TryGetValue позволяет разобраться как с корректностью аргумента, так и с наличием записи?

Про корректность аргументов там ничего не сказано.
Я только хочу сказать, что эти функции имеют другую задачу.
s> Давайте назовем результат TryGetValue вместо кода возврата признаком успеха. Это изменит суть претензий?
Ну если true и false считать признаками успеха, то да.

s> s>> И что будете делать при обнаружении бага или изменении требований? Считать вероятность или исправлять?


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


s> Меня не очень интересуют политики разрешения на изменение кода в вашей конторе. Но сам факт того что вы допускаете изменения, но не допускаете изменения поведения мне странен.

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

s> s>> Пусть не всегда. Но веские причины все-же не названы. Отсылка к OCR здесь ложная, т.к. ситуация другая.


s> AN>Как раз именно абсолютно такая же, считайте что данная часть модуля подает команды на сканирование документа.


s> Битая команда и нераспознаный в корректных данных символ — это весьма далекие ситуации.

Из-за этой команды головка хреново синхронизировалась со сканером и символ/строку уже не распознать, их может просто не быть там.

s> s>> AN>А отчего микрософт не рекомендует его ловить, а делает так?


s> s>> Вопрос с подвохом. Покажите мне для начала то место где микрософт не рекомендует ловить исключения WriteLine.


s> AN>Подобные вещи обычно находятся в коде, на такие мелочи они не размениваются.


s> Т.е. микрософту вы приписали тезисы вашей фантазии, разыгравшейся на почве примеров MSDN?


s> s>> Как считаете, для чего дан перечень исключений методов WriteLine, разве для того что бы их не ловили?

вопрос в том что это даст практически?

s> AN>Ок давайте будем ловить. Понравилось?


s> AN>
s> AN>


s> Я чувствую что этим безграмотным примером вы хотели ввести меня в какие-то противоречия, а не показать свое умение работы с исключениями. Потому комментировать его не буду. Но так же вижу, что у вас нет ответа на вопрос, зачем перечень исключений WriteLine представлен в MSDN...


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

s> s>> Показать вам код, который вышибет исключение из процитированного примера ровно в строчке WriteLine?


s> AN>И что даст это исключение для пользователя, в данном случае?


s> Открою секрет, что ловля исключений подразумевает не только показ MessageBox-а пользователю. В частности, например, гашение исключения позволит коду работать дальше, невзирая на случившиеся проблемы.

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

s> Проброс его наверх предоставит выбор вызывающему коду, обертывание позволит классифицировать исключение специальным образом.

Ну это если возможны варианты. А если есть всегда в данной части кода только вариант
с "гашением"?
s> В любом случае, если код данного уровня не предполагает о том, как должно быть обработано исключение, он и не должен его перехватывать и уж тем более показывать пользователю MessageBox.
Так что же нужно делать по этому исключению?
вот именно это и хотелось бы узнать.

s> Вернемся к посылу

s>

s> Давайте попросим код ошибки от Console.WriteLine и будем извещать пользователя если что не так

s> Механизм исключений для того и предназначен, что бы извещать пользователя, разработчика, или еще кого. Но делает это он именно на том уровне, где стоят обработчики. Тыкать обработчики на каждый вызов — не очень умно.
А есть вариант "глобального гашения"?

Понимаете, я не явлюсь противником использования исключений, а только хочу сказать, что их использование не подразумевает 100% покрытие. Нам нужна какая либо реакция на ошибку и не всегда нужно кричать об ошибке.
Ну типа выезжаю я на перекресток по главной улице и вижу машину которая также думает, что едет по главной. Да можно и посигналить и дождаться стражей порядка после аварии, но можно и просто притормозить. Конечно, в этом случае никто не узнает о нарушении. Но вопрос в том, что будет лучше в определенных ситуациях: кричать о нарушении или промолчать?
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[42]: Как не надо писать код
От: AlexNek  
Дата: 25.04.11 21:25
Оценка:
Здравствуйте, samius, Вы писали:

s> s>> Походу вы собираетесь и дальше препираться на тему можно ли трактовать результат TryGetValue кодом возврата, вместо того что бы согласиться что TryGetValue позволяет разобраться как с корректностью аргумента, так и с наличием записи?


s> AN>Про корректность аргументов там ничего не сказано.


s> см. секцию исключений

Мы вроде о Return Value говорили.

s> s>> Битая команда и нераспознаный в корректных данных символ — это весьма далекие ситуации.


s> AN>Из-за этой команды головка хреново синхронизировалась со сканером и символ/строку уже не распознать, их может просто не быть там.


s> Во! Из-за битой команды может пострадать результат сканирования, потому ситуации с битыми командами надо как минимум протоколировать и разбираться с ними, что бы максимально исключить возможность порчи данных команды.

С этим можно разбираться на этапе отладки, пользователь пересылать логи не будет.
s> Однако ситуация с нераспознаванием символа/строки может случиться и с валидной командой для головки, например из-за дефекта носителя. Это вообще норма, с этим ничего сделать нельзя, в этом софт не виноват и крайних искать не надо, так же как и исправлять что-либо. Т.е. одно может быть следствием другого, но не признаком другого.
В данном случае, пользователь просто получит чистый лист с надписью — нет обмена со сканером. И произойти это может по многим причинам, например вместо сканера подключили принтер.
Смысл в том что я рассматриваю функцию в конексте, вы же хотите ее рассматривать обобщенно. Для обобшенной функции нужно было делать именно так как вы говорите.
Для конкретного контекста по барабану, либо функция будет кричать, затем мы будет крик игнорировать наверху, и затем выдавать "нулевые данные", либо функция будет сразу выдавать "нулевые данные"

s> s>> s>> Как считаете, для чего дан перечень исключений методов WriteLine, разве для того что бы их не ловили?


s> AN>вопрос в том что это даст практически?


s> Практически это дает контроль над исключениями, возникшими внутри WriteLine. Т.е. программист имеет возможность обрабатывать их согласно постановке задачи.

Вот как раз и подошли к отличию "общих" функций от "конкретных".
Для "конкретных" не нужна никакая возможность выбора пути 1 или пути 2. Путь уже задан контекстом.
s> Обычно это не требуется, но если взять тот же пример, когда работа не должна убиваться при ошибке вывода в консоль (IO или FormatException), программист может обработать эту ситуацию.
И как ее обработать глобально? Делать враппер?
s> В другом случае он не будет спеицальным образом обрабатывать эти исключения и получит FailFast, который позволит увидеть проблему на раннем этапе.
Да плевать мне на консоль, единственная ее полезность вывод информации, а если этой возможности нет, то она мне нафиг не нужна.

s> AN>Вообще то в консольной программе мессаже бох не должен вообще появляться.


s> Это была не моя идея. Но там вместо MessageBox может стоять запись в лог файл.

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

s> Я тут не вижу противоречия. Если программа должна плевать — она может позволить себе плевать и следовать нормальному пути.

И какой ценой это достигается?
s> Если не должна плевать — может позволить обрабатывать исключение на этом же уровне или выше.
"Если" в данном случае просто не существует, есть только один единственный путь, по которому разрешено идти.

s> s>> AN>И что даст это исключение для пользователя, в данном случае?


s> s>> Открою секрет, что ловля исключений подразумевает не только показ MessageBox-а пользователю. В частности, например, гашение исключения позволит коду работать дальше, невзирая на случившиеся проблемы.

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

s> AN>То бишь вначале генерим то что нам не нужно, а после пытаемся это игнорировать.


s> Нужно или нет — решать будет вызывающий код. А в случаях, когда требуется обеспечить продолжение работы, сохранение лога можно обеспечить и из вызываемого кода, не возбуждая исключение. Однако, в данном случае, я не вижу смысла пересылки заведомо битой команды, посланной с рассогласованными данными.

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

s> s>> Проброс его наверх предоставит выбор вызывающему коду, обертывание позволит классифицировать исключение специальным образом.

Это все верно для "библиотечной" функции.

s> AN>Ну это если возможны варианты. А если есть всегда в данной части кода только вариант

s> AN>с "гашением"?

s> Хотя бы сбросить в лог для дальнейшего разбора полетов.

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

s> s>> В любом случае, если код данного уровня не предполагает о том, как должно быть обработано исключение, он и не должен его перехватывать и уж тем более показывать пользователю MessageBox.

В том и дело что код данноего уровня должне игнорировать исключение и послать "нулевые данные"

s> AN>Так что же нужно делать по этому исключению?

s> AN>вот именно это и хотелось бы узнать.

s> Выяснять и устранять причины битых данных. Если причин нет, то исключение не помеха, а страж.

И как же выяснить и усранить причину не вывода в консоль?

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


s> AN>А есть вариант "глобального гашения"?


s> Любое глобальное решение не подразумевает продолжение работы с места возбуждения без оборачивания кода в try/catch.

Вот именно это я хотел сказать, нафига заниматься пустым обворачиванием?

s> AN>Понимаете, я не явлюсь противником использования исключений, а только хочу сказать, что их использование не подразумевает 100% покрытие. Нам нужна какая либо реакция на ошибку и не всегда нужно кричать об ошибке.


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

Нужно ещ определится является ли нулевой буфер следствием ошибки в логике программы или это просто возможные данные?

s> AN>Ну типа выезжаю я на перекресток по главной улице и вижу машину которая также думает, что едет по главной. Да можно и посигналить и дождаться стражей порядка после аварии, но можно и просто притормозить. Конечно, в этом случае никто не узнает о нарушении. Но вопрос в том, что будет лучше в определенных ситуациях: кричать о нарушении или промолчать?


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

Где Вы увидели рассогласование данных? Есть неверные данные на входе. Вы считает что их не следует передавать дальше, а согласно задания нужно в этом случае передавать "нулевые данные".
s> Если после вы захотите разобраться, отчего такой глюк произошел, у вас должна быть хоть какая-то информация. Я не настаиваю что это должна быть ажурная надпись на airbag-е, выскочившая в процессе экстренного маневрирования (аналог MessageBox-а). Но хоть что-то, с чем сервисмен разберется, подключив диагностическую колодку.
Вот этого как раз и не требуется, в данном конкретном случае.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[43]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 26.04.11 08:12
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> см. секцию исключений

AN>Мы вроде о Return Value говорили.
Я говорил о том что вызывающему можно узнать как о нарушении/соблюдении контракта, так и об удаче завершения, и делать между ними различия.

s>> Во! Из-за битой команды может пострадать результат сканирования, потому ситуации с битыми командами надо как минимум протоколировать и разбираться с ними, что бы максимально исключить возможность порчи данных команды.

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

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

Я говорю об ошибках формирования команды для сканера и то что они будут провоцировать 100% неадекватное поведение сканера. Но мне уже надоело об этом говорить.

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

Относительно чего тут обобщение возникает?
AN>Для конкретного контекста по барабану, либо функция будет кричать, затем мы будет крик игнорировать наверху, и затем выдавать "нулевые данные", либо функция будет сразу выдавать "нулевые данные"
Дак напишите что бы она всегда выдавала "нулевые данные", раз по барабану. Меньше кода будет.

s>> Обычно это не требуется, но если взять тот же пример, когда работа не должна убиваться при ошибке вывода в консоль (IO или FormatException), программист может обработать эту ситуацию.

AN>И как ее обработать глобально? Делать враппер?
Выделять абстракцию
s>> В другом случае он не будет спеицальным образом обрабатывать эти исключения и получит FailFast, который позволит увидеть проблему на раннем этапе.
AN>Да плевать мне на консоль, единственная ее полезность вывод информации, а если этой возможности нет, то она мне нафиг не нужна.
Прекрасно Результат будете netsend-ом пользователю высылать?

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

Из обработчика уже не впрыгнуть обратно, если только им не каждый чих обернут, что бы иметь возможность перейти к следующему чиху. Потому выделение абстракции тут довольно разумный компромисс, который позволит не тыкать обработчики на каждый вызов.
s>> Я тут не вижу противоречия. Если программа должна плевать — она может позволить себе плевать и следовать нормальному пути.
AN>И какой ценой это достигается?
небольшой. Выделение абстракции + указание нужной политики. Код даже не будет изменяться при смене политики.
s>> Если не должна плевать — может позволить обрабатывать исключение на этом же уровне или выше.
AN>"Если" в данном случае просто не существует, есть только один единственный путь, по которому разрешено идти.
А как же путь "этапа отладки"? Выше вы явно обозначили что на этапе отладки что-то там решается, значит там другой код? Иначе если тот же, то отладку он только запутает.

AN>Но для гашения исключения нужно оборачивать каждый вызов. Или?

выделять абстракцию

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

Если он так же требует скрывать факт формирования неверной команды, то я умываю руки.

s>> s>> Проброс его наверх предоставит выбор вызывающему коду, обертывание позволит классифицировать исключение специальным образом.

AN>Это все верно для "библиотечной" функции.
Компилятор не делает разницы между "библиотечными" функциями и не "библиотечными". Потому вышеописанное верно для всех функций.

s>> Хотя бы сбросить в лог для дальнейшего разбора полетов.

AN>Лог может выводить и сама функция если это требуется. Зачем наполнять ведро зелеными помидорами и затем их выбрасывать, чтобы передать дальше пустое ведро?
Блин, нет слов, одни эмоции! У вас функция что ли будет решать, заполнять ли ведро помидорами? Сделайте так что бы решала конфигурация а не функция, тогда управлять, что делать с ведром (совать в лог, кидать исключение, либо жевать на месте) можно будет не перекомпилируя. Но это не должно оставаться в том виде, что сейчас. Я бы так не сделал, но вам виднее.

AN>В том и дело что код данноего уровня должне игнорировать исключение и послать "нулевые данные"



s>> Выяснять и устранять причины битых данных. Если причин нет, то исключение не помеха, а страж.

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

s>> Любое глобальное решение не подразумевает продолжение работы с места возбуждения без оборачивания кода в try/catch.

AN>Вот именно это я хотел сказать, нафига заниматься пустым обворачиванием?
Пустым как раз и нафига. Надо заниматься оборачиванием с пониманием ради чего. Например, выделение абстракции над консолью позволит оборачивать не все вызовы консоли, а только те что в реализации абстракции. А их O(1) штук относительно объема кода всей программы.

AN>Нужно ещ определится является ли нулевой буфер следствием ошибки в логике программы или это просто возможные данные?

Нулевой — это вопрос. А является ли ошибкой переполненный bufferLength?

AN>Где Вы увидели рассогласование данных? Есть неверные данные на входе. Вы считает что их не следует передавать дальше, а согласно задания нужно в этом случае передавать "нулевые данные".

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

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

AN>Вот этого как раз и не требуется, в данном конкретном случае.
На том и остановимся.
Re[44]: Как не надо писать код
От: AlexNek  
Дата: 26.04.11 13:07
Оценка:
Здравствуйте, samius, Вы писали:

s> s>> см. секцию исключений


s> AN>Мы вроде о Return Value говорили.


s> Я говорил о том что вызывающему можно узнать как о нарушении/соблюдении контракта, так и об удаче завершения, и делать между ними различия.

Но это нельзя сделать исключительно из значения поля возврата.

s> s>> Во! Из-за битой команды может пострадать результат сканирования, потому ситуации с битыми командами надо как минимум протоколировать и разбираться с ними, что бы максимально исключить возможность порчи данных команды.


s> AN>С этим можно разбираться на этапе отладки, пользователь пересылать логи не будет.


s> И что, на этапе отладки у вас один код, в продакшне другой?

В продакшин нет столь подробных логов.

s> AN>В данном случае, пользователь просто получит чистый лист с надписью — нет обмена со сканером. И произойти это может по многим причинам, например вместо сканера подключили принтер.


s> Я говорю об ошибках формирования команды для сканера и то что они будут провоцировать 100% неадекватное поведение сканера. Но мне уже надоело об этом говорить.

Так именно этого и нет, вы отчего то это себе представили.

s> AN>Смысл в том что я рассматриваю функцию в контексте, вы же хотите ее рассматривать обобщенно. Для обобшенной функции нужно было делать именно так как вы говорите.


s> Относительно чего тут обобщение возникает?

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

s> AN>Для конкретного контекста по барабану, либо функция будет кричать, затем мы будет крик игнорировать наверху, и затем выдавать "нулевые данные", либо функция будет сразу выдавать "нулевые данные"


s> Дак напишите что бы она всегда выдавала "нулевые данные", раз по барабану. Меньше кода будет.

"Нулевые данные" нужны в случае каких либо ошибочных ситуаций.

s> s>> Обычно это не требуется, но если взять тот же пример, когда работа не должна убиваться при ошибке вывода в консоль (IO или FormatException), программист может обработать эту ситуацию.


s> AN>И как ее обработать глобально? Делать враппер?


s> Выделять абстракцию

А более определенно?

s> s>> В другом случае он не будет специальным образом обрабатывать эти исключения и получит FailFast, который позволит увидеть проблему на раннем этапе.


s> AN>Да плевать мне на консоль, единственная ее полезность вывод информации, а если этой возможности нет, то она мне нафиг не нужна.


s> Прекрасно Результат будете netsend-ом пользователю высылать?

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

s> AN>Запись в лог файл и так будет в обработчике ошибок, но мне нужно при этом игнорировать все ошибки вывода на консоль для продолжения работы программы, т.е. нужно специально писать обвертку для заглушки исключений.


s> s>> Я тут не вижу противоречия. Если программа должна плевать — она может позволить себе плевать и следовать нормальному пути.


s> AN>И какой ценой это достигается?


s> небольшой. Выделение абстракции + указание нужной политики. Код даже не будет изменяться при смене политики.

Примерчик можно?

s> s>> Если не должна плевать — может позволить обрабатывать исключение на этом же уровне или выше.


s> AN>"Если" в данном случае просто не существует, есть только один единственный путь, по которому разрешено идти.


s> А как же путь "этапа отладки"? Выше вы явно обозначили что на этапе отладки что-то там решается, значит там другой код? Иначе если тот же, то отладку он только запутает.

На этапе отладки только больше информации, и то "по заказу"

s> AN>Но для гашения исключения нужно оборачивать каждый вызов. Или?


s> выделять абстракцию

сорри, слишком абстрактно .....

s> AN>Ну из того, что Вы не видите смысла, из за этого не следует, что ее не нужно посылать. Долго объяснять зачем, но так требует протокол устройства.


s> Если он так же требует скрывать факт формирования неверной команды, то я умываю руки.

Требуется при любой ошибочной ситуации передачи посылать "пустую команду".

s> s>> s>> Проброс его наверх предоставит выбор вызывающему коду, обертывание позволит классифицировать исключение специальным образом.


s> AN>Это все верно для "библиотечной" функции.


s> Компилятор не делает разницы между "библиотечными" функциями и не "библиотечными". Потому вышеописанное верно для всех функций.

А при чем здесь компилятор?
Вот скажем два "абстрактных" варианта, используются в одном единственном месте.
Насколько они эквивалентны?
if (f(ref x) == error)
{
 x = 0
}
...
f(ref x)
{
 if (input_error)
 {
   return error;
 }  
}


f(ref x);
...
f(ref x)
{
 if (input_error)
 {
   x = 0;
 }
}


s> s>> Хотя бы сбросить в лог для дальнейшего разбора полетов.


s> AN>Лог может выводить и сама функция если это требуется. Зачем наполнять ведро зелеными помидорами и затем их выбрасывать, чтобы передать дальше пустое ведро?


s> Блин, нет слов, одни эмоции! У вас функция что ли будет решать, заполнять ли ведро помидорами? Сделайте так что бы решала конфигурация а не функция, тогда управлять, что делать с ведром (совать в лог, кидать исключение, либо жевать на месте) можно будет не перекомпилируя. Но это не должно оставаться в том виде, что сейчас. Я бы так не сделал, но вам виднее.


s> AN>В том и дело что код данного уровня должен игнорировать исключение и послать "нулевые данные"


s>

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

s> s>> Выяснять и устранять причины битых данных. Если причин нет, то исключение не помеха, а страж.


s> AN>И как же выяснить и устранить причину не вывода в консоль?


s> Для начала обеспечить разработчика информацией о том что вывод в консоль окончился неудачей.

Для чего? Программа отработала как требовалось.
s> Если этого нет, то никто и не узнает, что там в консоль чего-то не попало. А потом уж разработчик должен включать голову, как выяснить причину и устранить.
Как и говорил, в общем случае это все верно, но когда, допустим я запускаю программу из другой программы, то вывод на консоль меня совсем не интересует.

s> AN>Нужно ещ определится является ли нулевой буфер следствием ошибки в логике программы или это просто возможные данные?


s> Нулевой — это вопрос. А является ли ошибкой переполненный bufferLength?

По идее это также ошибка.

s> AN>Где Вы увидели рассогласование данных? Есть неверные данные на входе. Вы считает что их не следует передавать дальше, а согласно задания нужно в этом случае передавать "нулевые данные".


s> Передавайте, если вам не интересна причина возникновения неверных данных.

Именно в данном случае неинтересна. Было задание передать ошибочные данные, передать их нельзя, поэтому передалась только информация что были какие то данные.
avalon 1.0rc3 rev 380, zlib 1.2.3
Re[45]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 26.04.11 14:22
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> Я говорил о том что вызывающему можно узнать как о нарушении/соблюдении контракта, так и об удаче завершения, и делать между ними различия.

AN>Но это нельзя сделать исключительно из значения поля возврата.
Никто не утвреждал что это делается исключительно возвращаемым значением.

s>> И что, на этапе отладки у вас один код, в продакшне другой?

AN>В продакшин нет столь подробных логов.
их что, кто-то убирает при выпуске версии?

s>> Я говорю об ошибках формирования команды для сканера и то что они будут провоцировать 100% неадекватное поведение сканера. Но мне уже надоело об этом говорить.

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

s>> Относительно чего тут обобщение возникает?

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

AN>"Нулевые данные" нужны в случае каких либо ошибочных ситуаций.

Исходный вариант функции не несет в себе анализа на некоторые ошибочные ситуации.

s>> AN>И как ее обработать глобально? Делать враппер?


s>> Выделять абстракцию

AN>А более определенно?
interface ILog { void WriteLine(string str); ... }


s>> AN>И какой ценой это достигается?


s>> небольшой. Выделение абстракции + указание нужной политики. Код даже не будет изменяться при смене политики.

AN>Примерчик можно?
выше

s>> Если он так же требует скрывать факт формирования неверной команды, то я умываю руки.

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

s>> Компилятор не делает разницы между "библиотечными" функциями и не "библиотечными". Потому вышеописанное верно для всех функций.

AN>А при чем здесь компилятор?
А при чем здесь "библиотечная" функция? Чем работа "библиотечных" функций отличается от остальных?

AN>Вот скажем два "абстрактных" варианта, используются в одном единственном месте.

AN>Насколько они эквивалентны?
AN>
if (f(ref x) == error)
AN>{
AN> x = 0
AN>}
AN>...
AN>f(ref x)
AN>{
AN> if (input_error)
AN> {
AN>   return error;
AN> }  
AN>}
AN>


AN>
f(ref x);
AN>...
AN>f(ref x)
AN>{
AN> if (input_error)
AN> {
AN>   x = 0;
AN> }
AN>}
AN>

Они достаточно эквивалентны в том плане, что я не понимаю, что они делают, что демонстрируют, и нафига там ref-ы.

s>>

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


s>> Для начала обеспечить разработчика информацией о том что вывод в консоль окончился неудачей.

AN>Для чего? Программа отработала как требовалось.
Есть простая истина. Не все что отработало как требовалось будет и дальше работать как требуется. Особенно после изменения требований или в других сценариях использования.

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

Это не означает что он будет благополучен.

s>> Нулевой — это вопрос. А является ли ошибкой переполненный bufferLength?

AN>По идее это также ошибка.

s>> AN>Где Вы увидели рассогласование данных? Есть неверные данные на входе. Вы считает что их не следует передавать дальше, а согласно задания нужно в этом случае передавать "нулевые данные".


s>> Передавайте, если вам не интересна причина возникновения неверных данных.

AN>Именно в данном случае неинтересна. Было задание передать ошибочные данные, передать их нельзя, поэтому передалась только информация что были какие то данные.
Мне начинает казаться, что вы и есть тот разработчик, которому доверили одну функцию, и кроме выполнения "задания" вас больше ничего не трогает.
Re[46]: Как не надо писать код
От: AlexNek  
Дата: 26.04.11 15:50
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> И что, на этапе отладки у вас один код, в продакшне другой?


s> AN>В продакшин нет столь подробных логов.


s> их что, кто-то убирает при выпуске версии?

Да, дядя препроцессор.

s> s>> Я говорю об ошибках формирования команды для сканера и то что они будут провоцировать 100% неадекватное поведение сканера. Но мне уже надоело об этом говорить.


s> AN>Так именно этого и нет, вы отчего то это себе представили.


s> Я слишком хорошо представляю как появляется то чего нет и пропадает то что есть, и что бывает, когда ничто не сигнализирует об изменении.

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

s> s>> Относительно чего тут обобщение возникает?


s> AN>Относительно точки зрения. Если рассматривать какую либо абстрактную функцию, где либо применяемую.


s> К абстрактным функциям, решающим абстрактные задачи где-либо, у меня нет претензий

То есть любой другой функции прерывания не нужны?

s> AN>"Нулевые данные" нужны в случае каких либо ошибочных ситуаций.


s> Исходный вариант функции не несет в себе анализа на некоторые ошибочные ситуации.

Вполне возможно. А что при добавлении исключения это анализ бы появился?

s> s>> AN>И как ее обработать глобально? Делать враппер?


s> s>> Выделять абстракцию


s> AN>А более определенно?


s>
s> interface ILog { void WriteLine(string str); ... }
s>


Ну так это и есть где то что я называю враппером
все равно ILog.WriteLine нельзя написать.

s> s>> AN>И какой ценой это достигается?


s> s>> небольшой. Выделение абстракции + указание нужной политики. Код даже не будет изменяться при смене политики.


s> AN>Примерчик можно?


s> выше

А что тогда политика?

s> s>> Если он так же требует скрывать факт формирования неверной команды, то я умываю руки.


s> AN>Требуется при любой ошибочной ситуации передачи посылать "пустую команду".


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

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

s> s>> Компилятор не делает разницы между "библиотечными" функциями и не "библиотечными". Потому вышеописанное верно для всех функций.


s> AN>А при чем здесь компилятор?


s> А при чем здесь "библиотечная" функция? Чем работа "библиотечных" функций отличается от остальных?


s> AN>Вот скажем два "абстрактных" варианта, используются в одном единственном месте.

s> AN>Насколько они эквивалентны?
s> AN>
if (f(ref x) == error)
s> AN>{
s> AN> x = 0
s> AN>}
s> AN>...
s> AN>f(ref x)
s> AN>{
s> AN> if (input_error)
s> AN> {
s> AN>   return error;
s> AN> }
s> AN>}
s> AN>


s> AN>
f(ref x);
s> AN>...
s> AN>f(ref x)
s> AN>{
s> AN> if (input_error)
s> AN> {
s> AN>   x = 0;
s> AN> }
s> AN>}
s> AN>


s> Они достаточно эквивалентны в том плане, что я не понимаю, что они делают, что демонстрируют, и нафига там ref-ы.

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

Попробую тогда словами описать, это было что то типа псевдокода
Вариант 1
Вызов функции с модифицируемым параметром Х
Если функция возвращает каким либо образом ошибку то параметр Х должен быть равен 0
Реализация функции с параметром Х
Если обнаружены неправильные входные параметры, то сообщаем об ошибке.

Вариант 2
Вызов функции с модифицируемым параметром Х
Реализация функции с параметром Х
Если обнаружены неправильные входные параметры, то устанавливаем параметр Х в 0


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


s> s>> Для начала обеспечить разработчика информацией о том что вывод в консоль окончился неудачей.


s> AN>Для чего? Программа отработала как требовалось.


s> Есть простая истина. Не все что отработало как требовалось будет и дальше работать как требуется. Особенно после изменения требований или в других сценариях использования.

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

s> AN>Как и говорил, в общем случае это все верно, но когда, допустим я запускаю программу из другой программы, то вывод на консоль меня совсем не интересует.


s> Это не означает что он будет благополучен.

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

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

Это ваше право так считать. Но в целом так и должно происходить. Пока задание не изменили/ приостановили его нужно выполнять. Иначе, если каждый будет делать так как считает более правильным командная работа будет весьма затруднена.
Однако никто не запрещает поднять вопрос, а отчего такую фигню нужно делать?
Исторически данная функция изначально имела исключительно лишь входные данные, одним из которых был параметр для вывода дополнительного символа. Все остальные параметры ей были не нужны и были сделаны "на вырост". Если параметр для вывода был в норме то выводился всего лишь дополнительный символ.
Человеку разрешили менять только данную функцию, не меняя поведение остального кода.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[47]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 26.04.11 16:41
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> их что, кто-то убирает при выпуске версии?

AN>Да, дядя препроцессор.
Жесть

s>> К абстрактным функциям, решающим абстрактные задачи где-либо, у меня нет претензий

AN>То есть любой другой функции прерывания не нужны?
Interrupt?

s>> AN>А более определенно?


s>>
s>> interface ILog { void WriteLine(string str); ... }
s>>


AN>Ну так это и есть где то что я называю враппером

Зря, это не враппер. Это абстракция. Враппером будет реализация этой абстракции.
AN>все равно ILog.WriteLine нельзя написать.
И не требуется. Для того абстракция и вводится, что бы не писать ILog.WriteLine, что по сути эквивалентно Console.WriteLine.

s>> выше

AN>А что тогда политика?
А это конкретная реализация, см. "стратегия".

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

AN>А именно этот код и не должнен посылать данные это всего лишь "врезка" в трубу.
Название не соответствует
AN>Буфер должен тогда быть равен нулю, а это эквивалентно "нулевым данным".
А сразу проверку с возвратом нельзя было сделать? Очень неочевидна логика метода.
AN>Можно конечно сделать и пару различных прерываний, чтобы вызывающий код имел больше информации о происходящем, но зачем?
Полегче с терминами. Если вы об исключениях, то прерывания — это из другой песни.

s>> Они достаточно эквивалентны в том плане, что я не понимаю, что они делают, что демонстрируют, и нафига там ref-ы.

AN>ref-ы — чтобы здесь меньше строк писать, да и указывают они на параметр который функция может модифицировать.

AN>Попробую тогда словами описать, это было что то типа псевдокода

AN>Вариант 1
AN>Вызов функции с модифицируемым параметром Х
AN>Если функция возвращает каким либо образом ошибку то параметр Х должен быть равен 0
AN>Реализация функции с параметром Х
AN>Если обнаружены неправильные входные параметры, то сообщаем об ошибке.
Сообщаем как? Допустимо ли значение параметра 0 при отсутствии ошибки?

AN>Вариант 2

AN>Вызов функции с модифицируемым параметром Х
AN>Реализация функции с параметром Х
AN>Если обнаружены неправильные входные параметры, то устанавливаем параметр Х в 0
Как узнать, что именно было обнаружено неправильного во входных данных?

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

Разве нельзя переопределить вывод в файл на диске только для чтения? Или пользователь ССЗБ?

s>> Это не означает что он будет благополучен.

AN>Конечно, но при нормальной работе вывод на консоль и так никто не видит. при запуске в ручном режиме, вывод на консоль является просто дополнительным бонусом. Если он невозможен, мы его просто игнорируем.
Для того что бы его проигнорировать, надо ввести либо абстракцию, либо try/catch-ить все вызовы WriteLine. Ни того ни другого желания я у вас не обнаружил. Так что походу игнорирование — это просто забивание на исключения.

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

AN>Это ваше право так считать. Но в целом так и должно происходить. Пока задание не изменили/ приостановили его нужно выполнять. Иначе, если каждый будет делать так как считает более правильным командная работа будет весьма затруднена.
Командная работа очень затруднена когда на команду одна думалка, компетентная разбираться в вопросах такого уровня. Хуже только когда их больше одной и у них разные мнения на этот счет.
AN>Однако никто не запрещает поднять вопрос, а отчего такую фигню нужно делать?
Подозреваю, что для этого надо оторвать думалку от решения более важных вопросов...
AN>Исторически данная функция изначально имела исключительно лишь входные данные, одним из которых был параметр для вывода дополнительного символа. Все остальные параметры ей были не нужны и были сделаны "на вырост". Если параметр для вывода был в норме то выводился всего лишь дополнительный символ.
AN>Человеку разрешили менять только данную функцию, не меняя поведение остального кода.
Интересно, сколько платят этому человеку?
Re[48]: Как не надо писать код
От: AlexNek  
Дата: 26.04.11 17:58
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> их что, кто-то убирает при выпуске версии?


s> AN>Да, дядя препроцессор.


s> Жесть

Всегда интересовал перевод этого слова, хотя бы на русский.

s> s>> К абстрактным функциям, решающим абстрактные задачи где-либо, у меня нет претензий


s> AN>То есть любой другой функции прерывания не нужны?


s> Interrupt? Фиг знает почему перещелкнуло, конечно Exception


s> s>> AN>А более определенно?


s> s>>
s> s>> interface ILog { void WriteLine(string str); ... }
s> s>>


s> AN>Ну так это и есть где то что я называю враппером


s> Зря, это не враппер. Это абстракция. Враппером будет реализация этой абстракции.

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

s> AN>все равно ILog.WriteLine нельзя написать.


s> И не требуется. Для того абстракция и вводится, что бы не писать ILog.WriteLine, что по сути эквивалентно Console.WriteLine.

В итоге все равно нужен синглетон или статик.

s> s>> выше


s> AN>А что тогда политика?


s> А это конкретная реализация, см. "стратегия".


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


s> AN>А именно этот код и не должнен посылать данные это всего лишь "врезка" в трубу.


s> Название не соответствует

Оно осталось каким и было, да и если не придираться можно сказать что это "трансформация нужная для вывода"

s> AN>Буфер должен тогда быть равен нулю, а это эквивалентно "нулевым данным".


s> А сразу проверку с возвратом нельзя было сделать? Очень неочевидна логика метода.

Так из за логики метод и попал на "доску почета"

s> AN>Можно конечно сделать и пару различных прерываний, чтобы вызывающий код имел больше информации о происходящем, но зачем?


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

Сорри, не знаю отчего переключился,

s> s>> Они достаточно эквивалентны в том плане, что я не понимаю, что они делают, что демонстрируют, и нафига там ref-ы.


s> AN>ref-ы — чтобы здесь меньше строк писать, да и указывают они на параметр который функция может модифицировать.


s> AN>Попробую тогда словами описать, это было что то типа псевдокода

s> AN>Вариант 1
s> AN>Вызов функции с модифицируемым параметром Х
s> AN>Если функция возвращает каким либо образом ошибку то параметр Х должен быть равен 0
s> AN>Реализация функции с параметром Х
s> AN>Если обнаружены неправильные входные параметры, то сообщаем об ошибке.

s> Сообщаем как?

Как именно, абсолютно неважно, "каким либо образом". Эта тоже абстракция только не интерфейсная

s> Допустимо ли значение параметра 0 при отсутствии ошибки?

Да, это ведь просто "врезка в трубу". Функция может здесь быть, а может и нет.

s> AN>Вариант 2

s> AN>Вызов функции с модифицируемым параметром Х
s> AN>Реализация функции с параметром Х
s> AN>Если обнаружены неправильные входные параметры, то устанавливаем параметр Х в 0

s> Как узнать, что именно было обнаружено неправильного во входных данных?

Для чего?

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


s> Разве нельзя переопределить вывод в файл на диске только для чтения? Или пользователь ССЗБ?

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

s> s>> Это не означает что он будет благополучен.


s> AN>Конечно, но при нормальной работе вывод на консоль и так никто не видит. при запуске в ручном режиме, вывод на консоль является просто дополнительным бонусом. Если он невозможен, мы его просто игнорируем.


s> Для того что бы его проигнорировать, надо ввести либо абстракцию, либо try/catch-ить все вызовы WriteLine. Ни того ни другого желания я у вас не обнаружил. Так что походу игнорирование — это просто забивание на исключения.

А вы много видели программ с абстракцией или try/catch на console?

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


s> AN>Это ваше право так считать. Но в целом так и должно происходить. Пока задание не изменили/ приостановили его нужно выполнять. Иначе, если каждый будет делать так как считает более правильным командная работа будет весьма затруднена.


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

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

s> AN>Исторически данная функция изначально имела исключительно лишь входные данные, одним из которых был параметр для вывода дополнительного символа. Все остальные параметры ей были не нужны и были сделаны "на вырост". Если параметр для вывода был в норме то выводился всего лишь дополнительный символ.

s> AN>Человеку разрешили менять только данную функцию, не меняя поведение остального кода.

s> Интересно, сколько платят этому человеку?

Сколько кому платят знает только бухгалтерия.
Просто каждого человека нужно использовать там где он больше всего приносит пользы, поэтому он участвует в проекте, но не пишет для него код, эта задача была исключением.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[49]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 26.04.11 20:06
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> AN>Да, дядя препроцессор.


s>> Жесть

AN>Всегда интересовал перевод этого слова, хотя бы на русский.
Жестоко (по отношению к препроцессору). Шутка. Так это вы нам показали код еще и без #ifdef-ов и [Conditional]-ов? Т.е. поработали за препроцессор?

s>> Зря, это не враппер. Это абстракция. Враппером будет реализация этой абстракции.

AN>Интерфейс без реализации в данном случае никак не поможет, но по крайней мере теперь я понимаю, что вы называете абстракцией.
не я один. Удивлен, что не было понимания.

s>> И не требуется. Для того абстракция и вводится, что бы не писать ILog.WriteLine, что по сути эквивалентно Console.WriteLine.

AN>В итоге все равно нужен синглетон или статик.
Нет, можно и без них, через передачу реализации.
Классический сигнлетон в этом плане вряд ли лучше Console.WriteLine. А глобальные изменяемые состояния приносят проблемы, в том числе при тестировании.

s>> А сразу проверку с возвратом нельзя было сделать? Очень неочевидна логика метода.

AN>Так из за логики метод и попал на "доску почета"
ясно

s>> AN>ref-ы — чтобы здесь меньше строк писать, да и указывают они на параметр который функция может модифицировать.

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

s>> AN>Если обнаружены неправильные входные параметры, то сообщаем об ошибке.


s>> Сообщаем как?

AN>Как именно, абсолютно неважно, "каким либо образом". Эта тоже абстракция только не интерфейсная
Как это? с абстракцией работает конкретный код, потому он должен знать заранее, как к этой абстракции обращаться.

s>> Допустимо ли значение параметра 0 при отсутствии ошибки?

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

s>> Как узнать, что именно было обнаружено неправильного во входных данных?

AN>Для чего?
что бы в другой раз сделать правильно.
Но я походу понял что к чему. Обсуждаемая функция была просто вхачена в вызывающую что бы модифицировать состояния локальных переменных, дабы изменить поведение не переделывая логику.

s>> Разве нельзя переопределить вывод в файл на диске только для чтения? Или пользователь ССЗБ?

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

s>> Для того что бы его проигнорировать, надо ввести либо абстракцию, либо try/catch-ить все вызовы WriteLine. Ни того ни другого желания я у вас не обнаружил. Так что походу игнорирование — это просто забивание на исключения.

AN>А вы много видели программ с абстракцией или try/catch на console?
Достаточно, тем более что есть абстракция из коробки. См. Trace и TraceListener. Правда штатный TextWriterTraceListener не ловит исключения TextWriter-а. Что в принципе верно, т.к. он не знает, что с ними делать. Но это легко исправить, когда есть конкретные требования по этому поводу, подсунув специального наследника.

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

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

s>> AN>Исторически данная функция изначально имела исключительно лишь входные данные, одним из которых был параметр для вывода дополнительного символа. Все остальные параметры ей были не нужны и были сделаны "на вырост". Если параметр для вывода был в норме то выводился всего лишь дополнительный символ.

s>> AN>Человеку разрешили менять только данную функцию, не меняя поведение остального кода.

s>> Интересно, сколько платят этому человеку?

AN>Сколько кому платят знает только бухгалтерия.
AN>Просто каждого человека нужно использовать там где он больше всего приносит пользы, поэтому он участвует в проекте, но не пишет для него код, эта задача была исключением.
Интерес мой больше к позиции конторы. Держать человека, которому доверяет историческую функцию и ничего более.
Re[50]: Как не надо писать код
От: AlexNek  
Дата: 26.04.11 21:33
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> AN>Да, дядя препроцессор.


s> s>> Жесть


s> AN>Всегда интересовал перевод этого слова, хотя бы на русский.


s> Жестоко (по отношению к препроцессору). Шутка.

Ага то то я по другому переводил

s> Так это вы нам показали код еще и без #ifdef-ов и [Conditional]-ов? Т.е. поработали за препроцессор?

Не а данная функция был просто скопирована из кода.

s> s>> Зря, это не враппер. Это абстракция. Враппером будет реализация этой абстракции.


s> AN>Интерфейс без реализации в данном случае никак не поможет, но по крайней мере теперь я понимаю, что вы называете абстракцией.


s> не я один. Удивлен, что не было понимания.

Не хочу делать предположений, но мне данное значение "абстракция" встречать еще не приходилось.

s> s>> И не требуется. Для того абстракция и вводится, что бы не писать ILog.WriteLine, что по сути эквивалентно Console.WriteLine.


s> AN>В итоге все равно нужен синглетон или статик.


s> Нет, можно и без них, через передачу реализации.

Странно как то себе это представляю передать на "10-й уровень".

s> s>> AN>ref-ы — чтобы здесь меньше строк писать, да и указывают они на параметр который функция может модифицировать.


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

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

s> s>> AN>Если обнаружены неправильные входные параметры, то сообщаем об ошибке.


s> s>> Сообщаем как?


s> AN>Как именно, абсолютно неважно, "каким либо образом". Эта тоже абстракция только не интерфейсная


s> Как это? с абстракцией работает конкретный код, потому он должен знать заранее, как к этой абстракции обращаться.

Вот именно это я лично называю абстракцией. В нашем примере это должно быть неважно будет ли это проверка конкретного значения кода ошибки или ловля эксепшина. Есть способ для сообщения об ошибке и есть способ для ее "детектирования".

s> s>> Допустимо ли значение параметра 0 при отсутствии ошибки?


s> AN>Да, это ведь просто "врезка в трубу". Функция может здесь быть, а может и нет.


s> Я не понимаю, что такое "врезка в трубу". И если функци здесь может не быть, то значит ее и не должно быть.

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

s> AN>Для чего?


s> что бы в другой раз сделать правильно.

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

s> s>> Разве нельзя переопределить вывод в файл на диске только для чтения? Или пользователь ССЗБ?


s> AN>Ну можно вообще комп не включать и спрашивать почему прога не работает.

s> AN>Вывод в файл — это основная функция, если она не работает, то тут как раз и нужно как то сообщить о проблемах.

s> s>> Для того что бы его проигнорировать, надо ввести либо абстракцию, либо try/catch-ить все вызовы WriteLine. Ни того ни другого желания я у вас не обнаружил. Так что походу игнорирование — это просто забивание на исключения.


s> AN>А вы много видели программ с абстракцией или try/catch на console?


s> Достаточно, тем более что есть абстракция из коробки. См. Trace и TraceListener.

Вроде речь шла именно о Console. Мне лично еще ни разу не попадался консольный вывод с try/catch.

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


s> AN>Во первых, думалка не думает о всех мелочах.


s> Потому я бы не стал выносить подобный вопрос на повестку, и максимум — решил бы его с кем-нибудь в рабочем порядке.

По поводу функции или по поводу использования исключений?
Функция уже давно исправлена, а модуль "заморожен".

s> AN>А во вторых, две разных думалки это вообще замечательно, когда между ними нет личных конфликтов, а только рабочие. Рождаются очень интересные идеи.


s> А еще более интересные умирают.

Пока мне такой ситуации не попадалось.

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

Я показал только то что он сделал неудовлетворительно, но есть масса других вещей которые он делает довольно неплохо. Ну и позиция конторы довольно либеральная. Действительно бесполезного человека, даже если он каким то образом туда прорвется, безусловно держать не будут. Но если человеку тяжело дается одна работа, но зато хорошо получается другая, дают ту работу, которая получается лучше.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[51]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 27.04.11 10:27
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> AN>Интерфейс без реализации в данном случае никак не поможет, но по крайней мереhttp://www.rsdn.ru/forum/NewMsg.aspx?mid=4250449#
Автор: AlexNek
Дата: 27.04.11
теперь я понимаю, что вы называете абстракцией.


s>> не я один. Удивлен, что не было понимания.

AN>Не хочу делать предположений, но мне данное значение "абстракция" встречать еще не приходилось.
встречайте. Так же здесь и, например, здесь.

s>> AN>В итоге все равно нужен синглетон или статик.


s>> Нет, можно и без них, через передачу реализации.

AN>Странно как то себе это представляю передать на "10-й уровень".
Вы же не передаете компарер с 1-го на 10-ый уровень? Так же и тут. Непосредственно вызывающий код может указать вызываемому конкретную реализацию. Но при необходимости можно и на 10-ый передать, используя IoC контейнеры.

s>> Как это? с абстракцией работает конкретный код, потому он должен знать заранее, как к этой абстракции обращаться.

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

s>> Достаточно, тем более что есть абстракция из коробки. См. Trace и TraceListener.

AN>Вроде речь шла именно о Console. Мне лично еще ни разу не попадался консольный вывод с try/catch.
Так TraceListener имеет наследника ConsoleTraceListener, который и сливает вывод в консоль. Таким образом это абстракция над выводом сообщений вообще, с реализацией из коробки для вывода сообщений в консоль в том числе.
AN>Мне лично еще ни разу не попадался консольный вывод с try/catch.
Это не важно, важно что вы собрались гарантировать продолжение вычислений при исключениях в Console.WriteLine и средств кроме try/catch, для этого нет. использование обертки позволяет не оборачивать try/catch каждый вызов, а абстракция позволяет гибко указывать любую обертку, в том числе более интересную, чем предоставляющую вывод в консоль.

AN>По поводу функции или по поводу использования исключений?

AN>Функция уже давно исправлена, а модуль "заморожен".
Угу, табу на изменения до очередной "врезки" в трубу. Но судьба той функции меня вообще не занимает, в отличии от ваших убеждений в том, что в ней все путем.

AN>Я показал только то что он сделал неудовлетворительно, но есть масса других вещей которые он делает довольно неплохо. Ну и позиция конторы довольно либеральная. Действительно бесполезного человека, даже если он каким то образом туда прорвется, безусловно держать не будут. Но если человеку тяжело дается одна работа, но зато хорошо получается другая, дают ту работу, которая получается лучше.

Тогда я спокоен и за человека и за контору. Потому как если бы было бы иначе — то держать человека, думать что бы ему разрешить что бы он что-нибудь не сломал, и платить ему за это деньги — было бы очень фигово. Но я знаю бюджетную контору, где 60% сотрудников в таком положении.
Re[52]: Как не надо писать код
От: AlexNek  
Дата: 27.04.11 13:21
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> AN>Интерфейс без реализации в данном случае никак не поможет, но по крайней мереhttp://www.rsdn.ru/forum/NewMsg.aspx?mid=4250449#
Автор: AlexNek
Дата: 27.04.11
теперь я понимаю, что вы называете абстракцией.


s> s>> не я один. Удивлен, что не было понимания.


s> AN>Не хочу делать предположений, но мне данное значение "абстракция" встречать еще не приходилось.


s> встречайте. Так же здесь и, например, здесь.

Две первых ссылки одинаковые, но там написано именно так, как и ожидалось
Как интерпретировать "Выделять абстракцию" в "использование интерфейсов/абстрактных функций" автоматом я не знаю.
Хотя вот попались русские фразы: "Оба типа модулей должны зависеть от абстракций", "Абстракции не должны зависеть от деталей", которые я бы просто не смог бы понять без контекста.

s> s>> AN>В итоге все равно нужен синглетон или статик.


s> s>> Нет, можно и без них, через передачу реализации.


s> AN>Странно как то себе это представляю передать на "10-й уровень".


s> Вы же не передаете компарер с 1-го на 10-ый уровень? Так же и тут.

А откуда вы знаете какой компарер захотел пользователь?
s> Непосредственно вызывающий код может указать вызываемому конкретную реализацию. Но при необходимости можно и на 10-ый передать, используя IoC контейнеры.
Ну и насколько это будет удобнее одной строки Console.WriteLine()?
И контейнеры волшебным образом знают все общие данные?

s> s>> Как это? с абстракцией работает конкретный код, потому он должен знать заранее, как к этой абстракции обращаться.


s> AN>Вот именно это я лично называю абстракцией. В нашем примере это должно быть неважно будет ли это проверка конкретного значения кода ошибки или ловля эксепшина. Есть способ для сообщения об ошибке и есть способ для ее "детектирования".


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

Так а конкретика на данном уровне и не интересует, конкретика важна будет при реализации.
Это типа аналог "Black box".

s> s>> Достаточно, тем более что есть абстракция из коробки. См. Trace и TraceListener.


s> AN>Вроде речь шла именно о Console. Мне лично еще ни разу не попадался консольный вывод с try/catch.


s> Так TraceListener имеет наследника ConsoleTraceListener, который и сливает вывод в консоль. Таким образом это абстракция над выводом сообщений вообще, с реализацией из коробки для вывода сообщений в консоль в том числе.

Имелось в виду Console.WriteLine c try/catch

s> AN>Мне лично еще ни разу не попадался консольный вывод с try/catch.


s> Это не важно, важно что вы собрались гарантировать продолжение вычислений при исключениях в Console.WriteLine и средств кроме try/catch, для этого нет. использование обертки позволяет не оборачивать try/catch каждый вызов, а абстракция позволяет гибко указывать любую обертку, в том числе более интересную, чем предоставляющую вывод в консоль.


Зачем усложнять простые вещи? Да для общего принципа вывода на консоль это все совершенно верно. Но в конкретном месте гораздо проще было бы использовать просто Console.WriteLine без всяких исключений.

s> AN>По поводу функции или по поводу использования исключений?

s> AN>Функция уже давно исправлена, а модуль "заморожен".

s> Угу, табу на изменения до очередной "врезки" в трубу. Но судьба той функции меня вообще не занимает, в отличии от ваших убеждений в том, что в ней все путем.

Я понимаю, что вы считаете данный подход в корне неверным. Я же только хочу сказать что не обязательно следует все мести под одну метлу.
Вот сделал я допустим, супер пупер код который можно и там применить, и там и еще где то. Если нужно А получите А, если нужно Б получите Б. И все хорошо и все работает. Но вот чтобы во всем разобраться другому человеку ему нужно раз пять читать документацию.
А если сделать тоже самое, но для конкретной задачи и для конкретного применения, другой человек без всякой документации сразу все поймет.

s> AN>Я показал только то что он сделал неудовлетворительно, но есть масса других вещей которые он делает довольно неплохо. Ну и позиция конторы довольно либеральная. Действительно бесполезного человека, даже если он каким то образом туда прорвется, безусловно держать не будут. Но если человеку тяжело дается одна работа, но зато хорошо получается другая, дают ту работу, которая получается лучше.


s> Тогда я спокоен и за человека и за контору. Потому как если бы было бы иначе — то держать человека, думать что бы ему разрешить что бы он что-нибудь не сломал, и платить ему за это деньги — было бы очень фигово. Но я знаю бюджетную контору, где 60% сотрудников в таком положении.

Ну это как бы несколько другое. Исправленная функция делала именно то, что требовалось, не больше и не меньше. А то что я глянул во внутрь — это скорее моя проблема Скажем иначе, в теме которой он занимается, он считается экспертом, и любые вопросы идут к нему. Он же и нашел, весьма быстро, в чем заключалась проблема.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re: Как не надо писать код
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 27.04.11 13:50
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


За 10 секунд получилось следующее: функция берет параметр buffer, сдвигает первые bufferLength его на единицу вправо с обрезанием последнего символа и добавлением PREFIX в начало. Если buffer пустой, то считается, что он заполнен нулями
Re[53]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 27.04.11 14:14
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> встречайте. Так же здесь и, например, здесь.

AN>Две первых ссылки одинаковые, но там написано именно так, как и ожидалось
Первая ссылка на общую статью, вторая на ее частный раздел
AN>Как интерпретировать "Выделять абстракцию" в "использование интерфейсов/абстрактных функций" автоматом я не знаю.
Абстрактный метод имеет непосредственную связь с абстракцией. А интерфейс это лишь совокупность абстрактных методов. Делегат тоже достаточно абстрактен для употребления его в роли абстракции от метода, на который он ссылается.
AN>Хотя вот попались русские фразы: "Оба типа модулей должны зависеть от абстракций", "Абстракции не должны зависеть от деталей", которые я бы просто не смог бы понять без контекста.
В определенном контексте они имеют смысл, и этот контекст можно ассоциировать с этими фразами, но понимать их вне контекста не нужно.

s>> Вы же не передаете компарер с 1-го на 10-ый уровень? Так же и тут.

AN>А откуда вы знаете какой компарер захотел пользователь?
Пользователь указал этот компарер предусмотренным способом. Если такого способа нет — значит не удастся узнать, как хочет пользователь сравнивать значения.

s>> Непосредственно вызывающий код может указать вызываемому конкретную реализацию. Но при необходимости можно и на 10-ый передать, используя IoC контейнеры.

AN>Ну и насколько это будет удобнее одной строки Console.WriteLine()?
Это зависит от намерений. Я уже упоминал о том, что при необходимости обеспечить выполнение кода, невзирая на исключения, которые могут (а могут и не) высыпать из WriteLine, нет другого способа кроме как обернуть вызов в try/catch (уже не одна строка с Console.WriteLine()).
Т.е. варианты следующие:
а) забить и писать Console.WriteLine
б) обернуть try/catch-ем каждый вызов
в) написать обертку с try/catch
в1) обеспечить гибкость передачи обертки через абстракцию (это все-таки не самостоятельный вариант, а лишь способ указания конкретной обертки)
Все варианты кроме а) решают задачу. Вариант а) задачу не решает, но очень удобен. Почему его можно предпочесть — вероятность вылета исключения из WriteLine довольно низка и ей можно принебречь, что все и делают. Да и я тоже, когда не решаю задачу гарантированного продолжения выполнения кода, невзирая на исключения из Console.WriteLine()

AN>И контейнеры волшебным образом знают все общие данные?

Зависит от конкретного контейнера. Есть достаточно волшебные.

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

AN>Так а конкретика на данном уровне и не интересует, конкретика важна будет при реализации.
Так это не абстракция, а просто опущенные детали.
AN>Это типа аналог "Black box".
Интерфейс взаимодействия с "Black box" должен быть достаточно "White", что бы BB предоставлял некий выход. Если мы не знаем что будет на выходе, то это не "Black box", а фактически "hole", за тем исключением что из Black hole ничего не вылетает обратно, кроме какого-то там теоретического излучения, которое никто не видел.

AN>Зачем усложнять простые вещи? Да для общего принципа вывода на консоль это все совершенно верно. Но в конкретном месте гораздо проще было бы использовать просто Console.WriteLine без всяких исключений.

А кто говорил о задаче гарантирования продолжения невзирая на изсключения из WriteLine?

AN>Я понимаю, что вы считаете данный подход в корне неверным. Я же только хочу сказать что не обязательно следует все мести под одну метлу.

AN>Вот сделал я допустим, супер пупер код который можно и там применить, и там и еще где то. Если нужно А получите А, если нужно Б получите Б. И все хорошо и все работает. Но вот чтобы во всем разобраться другому человеку ему нужно раз пять читать документацию.
AN>А если сделать тоже самое, но для конкретной задачи и для конкретного применения, другой человек без всякой документации сразу все поймет.
Во-первых, нужно выполнять задачу, если она все-таки стоит (об игноре исключений из WriteLine).
Во-вторых, в использовании принципов программирования не стоит ориентироваться на людей, которые их не знают и не понимают. Точнее не так.
Для начала все же лучше оценить, оправдывает ли цель средства. Если манипулирование абстракциями на таком уровне является проблемой для команды, то ну ее нафик, эту абстракцию. А может стоит подтянуть команду? Все же это не ахти какой уровень владения программированием.

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

Хорошо. А игнор исключений консоли — это все же не проблема. Точнее она не стоит остро и маловероятно что встанет.
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 27.04.11 14:56
Оценка:
Здравствуйте, Mystic, Вы писали:

M> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


M> AN>Интересно сколько времени вам понадобилось, что бы понять как функция точно работает?


M> За 10 секунд получилось следующее: функция берет параметр buffer, сдвигает первые bufferLength его на единицу вправо с обрезанием последнего символа и добавлением PREFIX в начало. Если buffer пустой, то считается, что он заполнен нулями

А откуда появилась информация об обрезании?
И что именно проверяется перед началом?
Какие действия предпринимаются для неправильных данных? Верны они или нет?
Вопросов можно еще найти довольно много и ответ во многих случаях нужно искать, а не "увидеть"
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[54]: Как не надо писать код
От: AlexNek  
Дата: 27.04.11 16:01
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> встречайте. Так же здесь и, например, здесь.


s> AN>Две первых ссылки одинаковые, но там написано именно так, как и ожидалось


s> Первая ссылка на общую статью, вторая на ее частный раздел

Сорри, не заметил.
s> AN>Как интерпретировать "Выделять абстракцию" в "использование интерфейсов/абстрактных функций" автоматом я не знаю.

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

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

s> AN>Хотя вот попались русские фразы: "Оба типа модулей должны зависеть от абстракций", "Абстракции не должны зависеть от деталей", которые я бы просто не смог бы понять без контекста.


s> В определенном контексте они имеют смысл, и этот контекст можно ассоциировать с этими фразами, но понимать их вне контекста не нужно.

Ну вот примерно так и получилось.

s> s>> Вы же не передаете компарер с 1-го на 10-ый уровень? Так же и тут.


s> AN>А откуда вы знаете какой компарер захотел пользователь?


s> Пользователь указал этот компарер предусмотренным способом. Если такого способа нет — значит не удастся узнать, как хочет пользователь сравнивать значения.

Тода возникает вопрос как передать этот способ?

s> s>> Непосредственно вызывающий код может указать вызываемому конкретную реализацию. Но при необходимости можно и на 10-ый передать, используя IoC контейнеры.


s> AN>Ну и насколько это будет удобнее одной строки Console.WriteLine()?


s> Это зависит от намерений. Я уже упоминал о том, что при необходимости обеспечить выполнение кода, невзирая на исключения, которые могут (а могут и не) высыпать из WriteLine, нет другого способа кроме как обернуть вызов в try/catch (уже не одна строка с Console.WriteLine()).

s> Т.е. варианты следующие:
s> а) забить и писать Console.WriteLine
s> б) обернуть try/catch-ем каждый вызов
s> в) написать обертку с try/catch
s> в1) обеспечить гибкость передачи обертки через абстракцию (это все-таки не самостоятельный вариант, а лишь способ указания конкретной обертки)
s> Все варианты кроме а) решают задачу. Вариант а) задачу не решает, но очень удобен. Почему его можно предпочесть — вероятность вылета исключения из WriteLine довольно низка и ей можно принебречь, что все и делают. Да и я тоже, когда не решаю задачу гарантированного продолжения выполнения кода, невзирая на исключения из Console.WriteLine()
Есть еще теоретический вариант а1 Console.WriteLine не дает исключений.

s> AN>И контейнеры волшебным образом знают все общие данные?


s> Зависит от конкретного контейнера. Есть достаточно волшебные.

В сказки я не верю еще с детства.

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


s> AN>Так а конкретика на данном уровне и не интересует, конкретика важна будет при реализации.


s> Так это не абстракция, а просто опущенные детали.

В моем случае камень — это абстракция скульптуры

s> AN>Это типа аналог "Black box".


s> Интерфейс взаимодействия с "Black box" должен быть достаточно "White", что бы BB предоставлял некий выход. Если мы не знаем что будет на выходе, то это не "Black box", а фактически "hole", за тем исключением что из Black hole ничего не вылетает обратно, кроме какого-то там теоретического излучения, которое никто не видел.

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

s> AN>Зачем усложнять простые вещи? Да для общего принципа вывода на консоль это все совершенно верно. Но в конкретном месте гораздо проще было бы использовать просто Console.WriteLine без всяких исключений.


s> А кто говорил о задаче гарантирования продолжения невзирая на изсключения из WriteLine?

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

s> AN>Я понимаю, что вы считаете данный подход в корне неверным. Я же только хочу сказать что не обязательно следует все мести под одну метлу.

s> AN>Вот сделал я допустим, супер пупер код который можно и там применить, и там и еще где то. Если нужно А получите А, если нужно Б получите Б. И все хорошо и все работает. Но вот чтобы во всем разобраться другому человеку ему нужно раз пять читать документацию.
s> AN>А если сделать тоже самое, но для конкретной задачи и для конкретного применения, другой человек без всякой документации сразу все поймет.

s> Во-первых, нужно выполнять задачу, если она все-таки стоит (об игноре исключений из WriteLine).

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

s> Если манипулирование абстракциями на таком уровне является проблемой для команды, то ну ее нафик, эту абстракцию.

Дело не в конкретной проблеме, а в общем подходе. И дело, в основном, упирается во время.
s> А может стоит подтянуть команду? Все же это не ахти какой уровень владения программированием.
Сегодня она одна, завтра совсем другая. Главный принцип "не выпендриваться".
Допустим, я знаю как мне написать "данный код" в 5 строк, но что бы в них разобраться и исправить нужно полчаса (даже и мне через пару лет). Поэтому лучше написать код в 20 строк, но который будет достаточно прозрачен.
Либо вот человек нашел/придумал новый клевый паттерн который позволяет работать с Х различными источниками. Хрен с ним что у нас только один источник, но вдруг когда будет много. Все казалось бы замечательно, только для изменений нужно вначале разобраться с паттерном, затем с кодом, и затем догадаться, где правильно будет изменять. Так, что дело далеко не в уровне подготовки команды.

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


s> Хорошо. А игнор исключений консоли — это все же не проблема. Точнее она не стоит остро и маловероятно что встанет.

Это просто был примерчик для сравнения вариантов.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[55]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 27.04.11 16:54
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


AN>Тексты на английском вполне понятны даже если читать отдельные предложения, чего я не могу сказать о подобных текстах на русском (хотя и звучит немного странно)

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

s>> Все варианты кроме а) решают задачу. Вариант а) задачу не решает, но очень удобен. Почему его можно предпочесть — вероятность вылета исключения из WriteLine довольно низка и ей можно принебречь, что все и делают. Да и я тоже, когда не решаю задачу гарантированного продолжения выполнения кода, невзирая на исключения из Console.WriteLine()

AN>Есть еще теоретический вариант а1 Console.WriteLine не дает исключений.
Мы совершенно точно знаем что он дает исключения. Вопрос лишь в том, на сколько серьезно мы относимся к обстоятельствам, при которых они возбуждаются, что бы принять решения об обработке исключений при обращении к консоли. Но считать что их там нет не можем.

s>> Зависит от конкретного контейнера. Есть достаточно волшебные.

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

s>> Так это не абстракция, а просто опущенные детали.

AN>В моем случае камень — это абстракция скульптуры
В почках?

AN>Не понимаю для чего нужна конкретика? Есть некий признак указывающий на ошибочное состояние входных данных его нужно проанализировать и сделать определенные действия.

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

s>> А кто говорил о задаче гарантирования продолжения невзирая на изсключения из WriteLine?

AN>Это как раз и есть два разных варианта действий. Вы говорите об использовании исключений всегда, я же говорю, что иногда удобнее использовать варианты без них.
В случае WriteLine нет вариантов без исключений. Вне зависимости от степени удобства, при определенных обстоятельствах исключения возбудятся. Наша воля лишь в том, обрабатывать их как-то или нет при написании кода. Я не настаиваю на том что их нужно обрабатывать в данном случае. Но тогда игнорировать их не получится, т.к. при возбуждении исключения выполнение кода будет прервано.

s>> Во-первых, нужно выполнять задачу, если она все-таки стоит (об игноре исключений из WriteLine).

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

s>> Если манипулирование абстракциями на таком уровне является проблемой для команды, то ну ее нафик, эту абстракцию.

AN>Дело не в конкретной проблеме, а в общем подходе. И дело, в основном, упирается во время.
Нечего возразить

s>> А может стоит подтянуть команду? Все же это не ахти какой уровень владения программированием.

AN>Сегодня она одна, завтра совсем другая. Главный принцип "не выпендриваться".
Выполнить задачу

AN>Допустим, я знаю как мне написать "данный код" в 5 строк, но что бы в них разобраться и исправить нужно полчаса (даже и мне через пару лет). Поэтому лучше написать код в 20 строк, но который будет достаточно прозрачен.

Если он не будет достаточно гибок для использования в разных условиях, то он может размножиться до 100 строк при необходимости использования в разных условиях. DRY.
Опять же на примере WriteTransformation, были прежде всего вопросы, зачем тут 20 строк, а не 5? И разве они прозрачны?

AN>Либо вот человек нашел/придумал новый клевый паттерн который позволяет работать с Х различными источниками. Хрен с ним что у нас только один источник, но вдруг когда будет много. Все казалось бы замечательно, только для изменений нужно вначале разобраться с паттерном, затем с кодом, и затем догадаться, где правильно будет изменять. Так, что дело далеко не в уровне подготовки команды.

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

s>> Хорошо. А игнор исключений консоли — это все же не проблема. Точнее она не стоит остро и маловероятно что встанет.

AN>Это просто был примерчик для сравнения вариантов.
Ок, тогда мы его усугубим. Предположим (уверен, что такого не будет, но тем не менее), что код, который пишет в консоль о прогрессе вычислений, потребовалось изменить так, что бы он сегодня писал в консоль, при нажатой галочке отправлял на почту, а в некоторой фазе луны сохранял бы вывод в БД или отправлял бы веб сервису. Типичный пример на принцип открытия-закрытия (OCP). Будете из 20 строчек делать 100 что бы "не выпендриваться", или примените приемы, недоступные коллег(е|ам) по команде?
Re[56]: Как не надо писать код
От: AlexNek  
Дата: 27.04.11 20:10
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> Все варианты кроме а) решают задачу. Вариант а) задачу не решает, но очень удобен. Почему его можно предпочесть — вероятность вылета исключения из WriteLine довольно низка и ей можно принебречь, что все и делают. Да и я тоже, когда не решаю задачу гарантированного продолжения выполнения кода, невзирая на исключения из Console.WriteLine()


s> AN>Есть еще теоретический вариант а1 Console.WriteLine не дает исключений.


s> Мы совершенно точно знаем что он дает исключения. Вопрос лишь в том, на сколько серьезно мы относимся к обстоятельствам, при которых они возбуждаются, что бы принять решения об обработке исключений при обращении к консоли. Но считать что их там нет не можем.


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

s> s>> Зависит от конкретного контейнера. Есть достаточно волшебные.


s> AN>В сказки я не верю еще с детства.


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


Была речь о "волшебстве", которое в итоге как то превращается в "глобальную переменную"

s> s>> Так это не абстракция, а просто опущенные детали.


s> AN>В моем случае камень — это абстракция скульптуры


s> В почках?

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

s> AN>Не понимаю для чего нужна конкретика? Есть некий признак указывающий на ошибочное состояние входных данных его нужно проанализировать и сделать определенные действия.


s> Конкретика здесь не нужна. Я лишь говорю о том, что неуточненные детали не есть абстракция.

Ну это смотря на каком уровне их рассматривать и для чего. Я никак не могу взять в толк для чего нужно опускаться еще ниже.

s> s>> А кто говорил о задаче гарантирования продолжения невзирая на изсключения из WriteLine?


s> AN>Это как раз и есть два разных варианта действий. Вы говорите об использовании исключений всегда, я же говорю, что иногда удобнее использовать варианты без них.


s> В случае WriteLine нет вариантов без исключений.

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

s> s>> А может стоит подтянуть команду? Все же это не ахти какой уровень владения программированием.


s> AN>Сегодня она одна, завтра совсем другая. Главный принцип "не выпендриваться".


s> Выполнить задачу


s> AN>Допустим, я знаю как мне написать "данный код" в 5 строк, но что бы в них разобраться и исправить нужно полчаса (даже и мне через пару лет). Поэтому лучше написать код в 20 строк, но который будет достаточно прозрачен.


s> Если он не будет достаточно гибок для использования в разных условиях, то он может размножиться до 100 строк при необходимости использования в разных условиях. DRY.

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

s> Опять же на примере WriteTransformation, были прежде всего вопросы, зачем тут 20 строк, а не 5? И разве они прозрачны?

Я уже повторял, что это не пример кода для подражания, а совсем наоборот.
Кстати, поначалу, вместе со скобками там и было 5 строк

s> AN>Либо вот человек нашел/придумал новый клевый паттерн который позволяет работать с Х различными источниками. Хрен с ним что у нас только один источник, но вдруг когда будет много. Все казалось бы замечательно, только для изменений нужно вначале разобраться с паттерном, затем с кодом, и затем догадаться, где правильно будет изменять. Так, что дело далеко не в уровне подготовки команды.


s> Дело в уровне. Если член команды знаком с паттерном (даже если не знаком с названием), ему не потребуется много времени на его понимание. Это как я скажу коллеге "цикл for" и он поймет, о чем речь, ему не надо будет изучать как работает этот цикл, понимать код, выдумывать как его изменять. Только другой уровень. Не слишком высокий. Этот уровень часто требуется при устройстве на работу. Достаточно часто, что бы о нем следовало иметь представление членам средней команды.

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

s> s>> Хорошо. А игнор исключений консоли — это все же не проблема. Точнее она не стоит остро и маловероятно что встанет.


s> AN>Это просто был примерчик для сравнения вариантов.


s> Ок, тогда мы его усугубим. Предположим (уверен, что такого не будет, но тем не менее), что код, который пишет в консоль о прогрессе вычислений, потребовалось изменить так, что бы он сегодня писал в консоль, при нажатой галочке отправлял на почту, а в некоторой фазе луны сохранял бы вывод в БД или отправлял бы веб сервису. Типичный пример на принцип открытия-закрытия (OCP). Будете из 20 строчек делать 100 что бы "не выпендриваться", или примените приемы, недоступные коллег(е|ам) по команде?

Однозначно сказать не могу, многое зависит от конкретной ситуации. Если работаю глубоко на "своем поле", на которое нехрен ходить, то вероятнее будут 20, если поле на пересечении или планируются частые изменения и эта сотня вполне адекватна, то вероятнее 100. А если решения равнозначны "по весу", то всегда более простое. Или если сотня будет иметь сильно много ограничений, то тогда 20.

Что из последнего помню. Есть у меня один "длинный" switch, раздражал он меня долго и придумал даже как он него избавится. Но потом сравнил решения и оставил как есть.
Когда на switch смотришь все понятно и нет вопросов. А так нужно думать, нафига то, нафига это, а как добавлять новую ветку и пр.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[2]: Как не надо писать код
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 28.04.11 02:00
Оценка:
Здравствуйте, Sinix, Вы писали:

S>За ref-ы, допущение того, что bufferLength может быть меньше 0, непроверку на переполнение — приговорить к пожизненному сопровождению своего кода.


Ну да — тут не всё так просто в общем случае. Например никто никогда не задумывался, почему Array.Length имеет тип int, а не uint (хотя на первый взгляд второй вариант логичнее)?
[КУ] оккупировала армия.
Re[57]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.04.11 04:04
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


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

Тогда можно предположить что требования выполнены.

AN>Была речь о "волшебстве", которое в итоге как то превращается в "глобальную переменную"

Это было бы проклятие, а не "волшебство".

AN>Предположим вам нужно своему взрослому ребенку объяснить правила движения авто на перекрестке. Будем ли мы для этого искать игрушечные машинки подходящего размера?

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

s>> Конкретика здесь не нужна. Я лишь говорю о том, что неуточненные детали не есть абстракция.

AN>Ну это смотря на каком уровне их рассматривать и для чего. Я никак не могу взять в толк для чего нужно опускаться еще ниже.
Я не заставляю опускаться ниже.

s>> В случае WriteLine нет вариантов без исключений.

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

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

Сначала вы писали что вас не волнует то что в консоли могут быть исключения, что ваша программа должна доработать, даже если в консоль невозможно писать. Без обработки исключений это обеспечить нельзя. Что тут непонятно? Если не нужны они вам в конкретном случае — не обрабатывайте. Тогда ваша программа споткнется о первое исключение, что бы вы там не представили о WriteLine-е.

s>> Если он не будет достаточно гибок для использования в разных условиях, то он может размножиться до 100 строк при необходимости использования в разных условиях. DRY.

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

AN>Если я год назад разбирался с каким либо паттерном это не значит что я его сегодня также хорошо помню. А если просто прочитал для общего развития...

Т.е. вы призываете не использовать что-то для решения задач только потому что сегодня вы не помните нечто так же хорошо? Допустим, есть алгоритм "Дейкстры", который решает вашу задачу, и который вы сегодня не помните так же хорошо. Будете изобретать свой?

AN>Уровень тут особой роли не играет (исключая "ниже планки"). Вот есть два человека с примерно одинаковым уровнем знаний, каждый пишет довольно внятный код, без выпендриваний, каждый понимает, что делает отдельная строчка/функция. Но если не рассказать концепт никто из них не поймет сразу как работает код другого.

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

s>> Ок, тогда мы его усугубим. Предположим (уверен, что такого не будет, но тем не менее), что код, который пишет в консоль о прогрессе вычислений, потребовалось изменить так, что бы он сегодня писал в консоль, при нажатой галочке отправлял на почту, а в некоторой фазе луны сохранял бы вывод в БД или отправлял бы веб сервису. Типичный пример на принцип открытия-закрытия (OCP). Будете из 20 строчек делать 100 что бы "не выпендриваться", или примените приемы, недоступные коллег(е|ам) по команде?

AN>Однозначно сказать не могу, многое зависит от конкретной ситуации. Если работаю глубоко на "своем поле", на которое нехрен ходить, то вероятнее будут 20, если поле на пересечении или планируются частые изменения и эта сотня вполне адекватна, то вероятнее 100. А если решения равнозначны "по весу", то всегда более простое. Или если сотня будет иметь сильно много ограничений, то тогда 20.
Т.е. все-таки существуют какие-то аспекты, которые перевешивают в сторону выпендривания?

AN>Что из последнего помню. Есть у меня один "длинный" switch, раздражал он меня долго и придумал даже как он него избавится. Но потом сравнил решения и оставил как есть.

AN>Когда на switch смотришь все понятно и нет вопросов. А так нужно думать, нафига то, нафига это, а как добавлять новую ветку и пр.
Существуют причины для избавления от свитча, существуют причины для сохранения свитча. Его длина не показатель для избавления.
Re[58]: Как не надо писать код
От: AlexNek  
Дата: 28.04.11 11:50
Оценка:
Здравствуйте, samius, Вы писали:

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


s> AN>Я же говорю теоретический, можно ведь предположить что есть такая же функция но без исключений.


s> Тогда можно предположить что требования выполнены.

Ну вот поэтому в данной функции и не было исключений.

s> AN>Была речь о "волшебстве", которое в итоге как то превращается в "глобальную переменную"


s> Это было бы проклятие, а не "волшебство".

"Console" и "GerServices()" я и называю "глобальными переменными".
Должно быть нечто видное "везде".

s> AN>Предположим вам нужно своему взрослому ребенку объяснить правила движения авто на перекрестке. Будем ли мы для этого искать игрушечные машинки подходящего размера?

s> AN>Вполне возможно обойтись и резинкой с конфеткой. Данная абстракция вполне достаточна.

s> В этой абстракции мы предполагаем по умолчанию что у машинки, представленной конфеткой, исправны тормоза, пока не оговорено обратное. То что за конфеткой скрывается машинка — это абстракция. То что тормоза исправны — это конкретика.

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

s> s>> Конкретика здесь не нужна. Я лишь говорю о том, что неуточненные детали не есть абстракция.


s> AN>Ну это смотря на каком уровне их рассматривать и для чего. Я никак не могу взять в толк для чего нужно опускаться еще ниже.


s> Я не заставляю опускаться ниже.

С каждым уровнем абстракции неуточненных деталей появляется все больше

s> s>> В случае WriteLine нет вариантов без исключений.


s> AN>Но ничто не запрещает нам их представить.


s> Угу, начальнику никто не запрещает представить что вы выполнили работу, бухгалтер представит ведомость, а вы в конце концов представите бутерброд с икрой


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

s> AN>Во, требования обработки исключений не стоит. Использовать WriteLine кто то еще, больше не будет. Тогда вопрос, а нафига они нам нужны в этом конкретном случае.


s> Сначала вы писали что вас не волнует то что в консоли могут быть исключения, что ваша программа должна доработать, даже если в консоль невозможно писать. Без обработки исключений это обеспечить нельзя. Что тут непонятно? Если не нужны они вам в конкретном случае — не обрабатывайте. Тогда ваша программа споткнется о первое исключение, что бы вы там не представили о WriteLine-е.

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

s> s>> Если он не будет достаточно гибок для использования в разных условиях, то он может размножиться до 100 строк при необходимости использования в разных условиях. DRY.


s> AN>(Но...), как и вариантов может быть довольно много, решается строго индивидуально.

s> AN>Но опять таки "Если он не будет достаточно гибок для использования в разных условиях". Здесь довольно часто нужен оптимальный компромисс. Почти все гибкое довольно сложное в какой либо проекции.

s> Негибкое в некоторой проекции тоже сложно. В проекции изменения требований.

Безусловно, поэтому и идет речь о компромиссе. Если в обозримом будущем не будет требоваться использования Х объектов, то для чего уже сейчас делать их поддержку. Однако, если после прийдется вообще все переделывать для поддержки Х объектов, так лучше предусмотреть их сейчас.
Какое то время назад, я считал, что нужно всегда делать "гибкие объекты". Сейчас так однозначно я уже не думаю.

s> AN>Если я год назад разбирался с каким либо паттерном это не значит что я его сегодня также хорошо помню. А если просто прочитал для общего развития...


s> Т.е. вы призываете не использовать что-то для решения задач только потому что сегодня вы не помните нечто так же хорошо? Допустим, есть алгоритм "Дейкстры", который решает вашу задачу, и который вы сегодня не помните так же хорошо. Будете изобретать свой?

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

s> AN>Уровень тут особой роли не играет (исключая "ниже планки"). Вот есть два человека с примерно одинаковым уровнем знаний, каждый пишет довольно внятный код, без выпендриваний, каждый понимает, что делает отдельная строчка/функция. Но если не рассказать концепт никто из них не поймет сразу как работает код другого.


s> Вы достаточно хорошо понимаете работу компилятора вместе с остальной командой, что бы не считать использование компилятора выпендриванием?

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

s> s>> Ок, тогда мы его усугубим. Предположим (уверен, что такого не будет, но тем не менее), что код, который пишет в консоль о прогрессе вычислений, потребовалось изменить так, что бы он сегодня писал в консоль, при нажатой галочке отправлял на почту, а в некоторой фазе луны сохранял бы вывод в БД или отправлял бы веб сервису. Типичный пример на принцип открытия-закрытия (OCP). Будете из 20 строчек делать 100 что бы "не выпендриваться", или примените приемы, недоступные коллег(е|ам) по команде?


s> AN>Однозначно сказать не могу, многое зависит от конкретной ситуации. Если работаю глубоко на "своем поле", на которое нехрен ходить, то вероятнее будут 20, если поле на пересечении или планируются частые изменения и эта сотня вполне адекватна, то вероятнее 100. А если решения равнозначны "по весу", то всегда более простое. Или если сотня будет иметь сильно много ограничений, то тогда 20.


s> Т.е. все-таки существуют какие-то аспекты, которые перевешивают в сторону выпендривания?


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

s> AN>Что из последнего помню. Есть у меня один "длинный" switch, раздражал он меня долго и придумал даже как он него избавится. Но потом сравнил решения и оставил как есть.

s> AN>Когда на switch смотришь все понятно и нет вопросов. А так нужно думать, нафига то, нафига это, а как добавлять новую ветку и пр.

s> Существуют причины для избавления от свитча, существуют причины для сохранения свитча. Его длина не показатель для избавления.

В данном случае, меня раздражала именно "длина". Я ведь не пишу рецепт "в каких случаях желательно избавляться от свитча". Хотя "длину в десяток экранов" (несколько преувеличено) я бы записал в него.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[59]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 28.04.11 12:30
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> Тогда можно предположить что требования выполнены.

AN>Ну вот поэтому в данной функции и не было исключений.
понятно

s>> AN>Была речь о "волшебстве", которое в итоге как то превращается в "глобальную переменную"


s>> Это было бы проклятие, а не "волшебство".

AN>"Console" и "GerServices()" я и называю "глобальными переменными".
По поводу консоли — можно согласиться. А GetServices с чего стал глобальным?
AN>Должно быть нечто видное "везде".
Для чего, и собственно что именно?

AN>Тормоза, в данном случае, нас не интересуют вообще, на данном уровне абстракции их вообще нет, машинка просто может останавливаться. По какой причине — не интересует.

Пусть не интересует
AN>Если рассматривать другую задачу, в которой будет важна сущность останова, то мы просто добавим объект в возможностью останова и с ограниченной возможностью останова. При этом реальный объект может тормозить из за наличия тормозов, а может и просто из за наличия троса сзади.
В исходной задаче вы сказали что "можно определить корректность аргументов". И это подразумевает некоторый способ, который не изменится при смене реализации абстракции.

s>> AN>Ну это смотря на каком уровне их рассматривать и для чего. Я никак не могу взять в толк для чего нужно опускаться еще ниже.


s>> Я не заставляю опускаться ниже.

AN>С каждым уровнем абстракции неуточненных деталей появляется все больше
да

s>> Сначала вы писали что вас не волнует то что в консоли могут быть исключения, что ваша программа должна доработать, даже если в консоль невозможно писать. Без обработки исключений это обеспечить нельзя. Что тут непонятно? Если не нужны они вам в конкретном случае — не обрабатывайте. Тогда ваша программа споткнется о первое исключение, что бы вы там не представили о WriteLine-е.

AN>Я просто хотел показать два различных варианта один с исключениями, другой без.
Нет варианта без исключений. Есть вариант без обработки исключений. Потому как нет такой WriteLine, которая бы не кидала исключений вообще никогда.
AN>Что нужно делать чтобы потом избавляться от них, и что вообще не нужно делать если их нет. При этом не для какого то общего случая, а для абсолютно конкретного.

s>> Негибкое в некоторой проекции тоже сложно. В проекции изменения требований.

AN>Безусловно, поэтому и идет речь о компромиссе. Если в обозримом будущем не будет требоваться использования Х объектов, то для чего уже сейчас делать их поддержку. Однако, если после прийдется вообще все переделывать для поддержки Х объектов, так лучше предусмотреть их сейчас.
AN>Какое то время назад, я считал, что нужно всегда делать "гибкие объекты". Сейчас так однозначно я уже не думаю.
Я не просил вас принимать решение сейчас. Я интересовался, есть ли причины, по которым вы можете использовать неочевидные для коллег приемы, т.е. выпендриваться по вашему. Вижу, что есть. Этого достаточно.

s>> Т.е. вы призываете не использовать что-то для решения задач только потому что сегодня вы не помните нечто так же хорошо? Допустим, есть алгоритм "Дейкстры", который решает вашу задачу, и который вы сегодня не помните так же хорошо. Будете изобретать свой?

AN>Я не призываю следовать всегда и везде каким либо установкам. Иногда это может быть целесообразно иногда нет. Хотя часто и нет полной уверенности как следует действовать в конкретной ситуации. Однако на выбор будет сильно влиять "режим работы" — командный или в одиночку.
Т.е. если командный, то будете склонны изобретать свой метод, вместо использования общеизвестного? Не ясна логика.

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

варианты не интересны. Есть что-то неочевидное для соседа. Будет ли алгоритм Дейкстры менее понятен для соседа, чем ваш велосипед?
AN>Если что то слышал но не помнишь, можно поискать и глянуть, а подойдет ли? Если решение кажется сложным но не придумывается проще можно вполне взять готовое снабдив комментарием на описание/название и т.п. Иногда можно вообще ничего не искать. Если на поиски нужно будет хотя бы полдня (при непредсказуемом результате), а написать можно за два, то нафига что искать.
А потом еще 2 дня объяснять команде, чего тут понаписано?

s>> Вы достаточно хорошо понимаете работу компилятора вместе с остальной командой, что бы не считать использование компилятора выпендриванием?

AN>По крайней мере мы пишем код вначале "для себя", а уж потом для компилятора.
AN>Можно было вообще никаких отступов не делать — это ведь лишняя работа компилятору.
Я не об этом спрашивал. Я привел пример неочевидного инструмента, который многие используют, не понимая принципов его работы, не считая его выпендриванием.
AN>Возможно необходимо пояснить что имелось в виду под "выпендриванием".
Поясните, будьте добры. Вы его упомянули в ответ на мое предложение подтянуть команду.

s>> Т.е. все-таки существуют какие-то аспекты, которые перевешивают в сторону выпендривания?


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

очевидно

s>> Существуют причины для избавления от свитча, существуют причины для сохранения свитча. Его длина не показатель для избавления.

AN>В данном случае, меня раздражала именно "длина". Я ведь не пишу рецепт "в каких случаях желательно избавляться от свитча". Хотя "длину в десяток экранов" (несколько преувеличено) я бы записал в него.
Ни в коем случае не призываю вас от него избавляться, не зная деталей. Но вот мне что интересно: в вашей команде считается выпендриванием оперирование абстракциями, но гипертрофированный свитч, по всей видимости, не является проблемой для понимания его работы?
Re[5]: Как не надо писать код
От: Sinix  
Дата: 28.04.11 15:09
Оценка:
Здравствуйте, koandrew, Вы писали:

S>>1. warning CS3001: Argument type 'uint' is not CLS-compliant

K>Ну это вообще говоря не проблема для авторов спецификации
CLS — Common Language Specification, не C# Language Specification. Осложнять жизнь при портировании кода под .net — не самый лучший способ завоевать популярность.

K>Ага, "640кб хватит всем". Проходили уже


Нет, просто для таких задач недостаточно примитивной абстракции над непрерывным сегментом памяти. И у гипотетического SlicedArray вполне может быть Length типа long (зачем мелочиться?).

K>Как ты думаешь, что будет, если выполнить этот код?

[k.o.]
Или code analysis warning, или OverflowException в рантайме при тестах, или ArgumentOutOfRange на клиенте. Всё зависит от уровня разработки.
[/k.o.]
Но в целом да, беззнаковый тип для размерностей может породить кучу интересных проблем как раз из-за отсутствия явно недопустимых значений.
Re[7]: Как не надо писать код
От: Sinix  
Дата: 28.04.11 15:51
Оценка:
Здравствуйте, koandrew, Вы писали:

K>Дык уже У массивов есть LongLength


Оно есть начиная с .NET 1.1. Позор на мою неседую голову, что ещё сказать.

S>>[k.o.]

S>>Или code analysis warning, или OverflowException в рантайме при тестах, или ArgumentOutOfRange на клиенте. Всё зависит от уровня разработки.
S>>[/k.o.]
K>Первое — возможно, второго и третьего не будет Просто код поведёт себя совсем не так, как того ожидает разработчик...
Кстати да, i у нас будет int. И в цикле нет доступа к массиву. А вот почему не будет overflow при checked-билде?

K>Да нет — тут проблема чисто в переполнениях и в том, что очень многие разработчики тупо не в курсе проблемы...

И не только в них. Если результат IndexOf() == uint.MaxValue — это значит что мы ничего не нашли, или что нашли последний элемент? Конечно можно отдавать Nullable<uint>, но, чую, это только самое начало проблем от использования uint для индексирования массивов/списков.
Re[60]: Как не надо писать код
От: AlexNek  
Дата: 28.04.11 16:55
Оценка:
Здравствуйте, samius, Вы писали:

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

я немного подчистил текст, если что лишнее убрал — не специально.

s> s>> AN>Была речь о "волшебстве", которое в итоге как то превращается в "глобальную переменную"


s> s>> Это было бы проклятие, а не "волшебство".


s> AN>"Console" и "GerServices()" я и называю "глобальными переменными".


s> По поводу консоли — можно согласиться. А GetServices с чего стал глобальным?

А сколько у вас имплементаций для "хранилища" сервисов?
Кроме того он может выглядеть и так
ServiceController.GetServices();

s> AN>Должно быть нечто видное "везде".


s> Для чего, и собственно что именно?

Что именно абсолютно не интересует (вполне возможно, что подобная формулировка режет слух но это просто различие в уровнях абстракций)
А для чего? Есть задача иметь доступ к чему то из любой части программы.
Ну типа Trace.WriteLine();

s> AN>Тормоза, в данном случае, нас не интересуют вообще, на данном уровне абстракции их вообще нет, машинка просто может останавливаться. По какой причине — не интересует.


s> Пусть не интересует


s> AN>Если рассматривать другую задачу, в которой будет важна сущность останова, то мы просто добавим объект в возможностью останова и с ограниченной возможностью останова. При этом реальный объект может тормозить из за наличия тормозов, а может и просто из за наличия троса сзади.


s> В исходной задаче вы сказали что "можно определить корректность аргументов". И это подразумевает некоторый способ, который не изменится при смене реализации абстракции.

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

s> s>> Сначала вы писали что вас не волнует то что в консоли могут быть исключения, что ваша программа должна доработать, даже если в консоль невозможно писать. Без обработки исключений это обеспечить нельзя. Что тут непонятно? Если не нужны они вам в конкретном случае — не обрабатывайте. Тогда ваша программа споткнется о первое исключение, что бы вы там не представили о WriteLine-е.


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


s> Нет варианта без исключений. Есть вариант без обработки исключений. Потому как нет такой WriteLine, которая бы не кидала исключений вообще никогда.

Держите

WriteLine()
{
}


Вы опять переходите на конкретику. Дело было не в конкретной функции WriteLine. А скажем так в "паттерне размышления".

s> s>> Т.е. вы призываете не использовать что-то для решения задач только потому что сегодня вы не помните нечто так же хорошо? Допустим, есть алгоритм "Дейкстры", который решает вашу задачу, и который вы сегодня не помните так же хорошо. Будете изобретать свой?


s> AN>Я не призываю следовать всегда и везде каким либо установкам. Иногда это может быть целесообразно иногда нет. Хотя часто и нет полной уверенности как следует действовать в конкретной ситуации. Однако на выбор будет сильно влиять "режим работы" — командный или в одиночку.


s> Т.е. если командный, то будете склонны изобретать свой метод, вместо использования общеизвестного? Не ясна логика.

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

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


s> варианты не интересны. Есть что-то неочевидное для соседа. Будет ли алгоритм Дейкстры менее понятен для соседа, чем ваш велосипед?

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

s> AN>Если что то слышал но не помнишь, можно поискать и глянуть, а подойдет ли? Если решение кажется сложным но не придумывается проще можно вполне взять готовое снабдив комментарием на описание/название и т.п. Иногда можно вообще ничего не искать. Если на поиски нужно будет хотя бы полдня (при непредсказуемом результате), а написать можно за два, то нафига что искать.


s> А потом еще 2 дня объяснять команде, чего тут понаписано?

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


s> s>> Вы достаточно хорошо понимаете работу компилятора вместе с остальной командой, что бы не считать использование компилятора выпендриванием?


s> AN>По крайней мере мы пишем код вначале "для себя", а уж потом для компилятора.

s> AN>Можно было вообще никаких отступов не делать — это ведь лишняя работа компилятору.

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


s> AN>Возможно необходимо пояснить что имелось в виду под "выпендриванием".


s> Поясните, будьте добры. Вы его упомянули в ответ на мое предложение подтянуть команду.

Ну, можно далеко не ходить за примером "выпендривания"
bufferLength = Math.Max(bufferLength, 0)

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

Вы же имели видимо в виду видимо "неизвестное использование"
Ну типа
return await ххх


А вот при чем здесь инструменты до меня не дошло.

s> s>> Существуют причины для избавления от свитча, существуют причины для сохранения свитча. Его длина не показатель для избавления.


s> AN>В данном случае, меня раздражала именно "длина". Я ведь не пишу рецепт "в каких случаях желательно избавляться от свитча". Хотя "длину в десяток экранов" (несколько преувеличено) я бы записал в него.


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

Что то я не припоминаю где это я мог упоминать.

s> но гипертрофированный свитч, по всей видимости, не является проблемой для понимания его работы?

Так а что там нужно понимать? Есть выбор и дохрена "комнат".
Нужно что новое — добавляешь "комнату" и все.

Можно было допустим "выпендрится" с атрибутами и забить "комнатки" в функции.
Тогда также было бы просто добавить "комнату", но зато общий код получился бы неочевидным, нужно было уже "думать" как, почему и зачем.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[62]: Как не надо писать код
От: AlexNek  
Дата: 28.04.11 22:27
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> По поводу консоли — можно согласиться. А GetServices с чего стал глобальным?


s> AN>А сколько у вас имплементаций для "хранилища" сервисов?


s> Обычно не больше одной

Так почему ее нельзя считать глобальной?

s> AN>Кроме того он может выглядеть и так

s> AN>ServiceController.GetServices();

s> У тех кто не видел проблем от глобальных состояний — может.

Микрософт их видимо обходит другим путем
s> s>> AN>Должно быть нечто видное "везде".

s> s>> Для чего, и собственно что именно?


s> AN>Что именно абсолютно не интересует (вполне возможно, что подобная формулировка режет слух но это просто различие в уровнях абстракций)


s> Под что именно я пытался уточнить, речь о глобальных состояниях только, или вообще о методах, классах?

Я имел в виду некий объект, доступ к которому может быть необходим из произвольного места кода. Объект может как хранить состояния, так и выполнять некую работу.
Каким образом это будет реализовано, глубоко фиолетово.

s> AN>А для чего? Есть задача иметь доступ к чему то из любой части программы.

s> AN>Ну типа Trace.WriteLine();

s> Хоть оно и из коробки, но это далеко не образец для подражания. Если при активном использовании Trace начать манипулировать TraceListener-ами во время выполнения в многопоточном приложении — будет большая каша, например.

Можно еще попробовать менять системные диски после загрузки ОС и проверить будет ли в этом случае каша.
Я начинаю подозревать что вы так называемый "практический типаж", есть у меня на работе хороший коллега с которым мы поначалу никак не могли найти общий язык. Я начинал ему говорить о проблеме на абстрактном уровне и он ну ничего не мог понять, зато когда приводил пару конкретных примеров, понимал мгновенно. Это ни хорошо, ни плохо, это просто другой тип мышления, который просто нужно учитывать при общении.
Хотя я пока не знаю точно как это учитывать при общении в форуме. Могу только сказать, что нам непросто понять друг друга в этом случае. Тут видимо спасут дополнительные вопросы. Ну это так, лирическое отступление

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

s> s>> В исходной задаче вы сказали что "можно определить корректность аргументов". И это подразумевает некоторый способ, который не изменится при смене реализации абстракции.


s> AN>Нет, это никак не подразумевает конкретный способ. Я даже не знаю какие будут аргументы и как их необходимо проверять. Я только знаю что должна быть проверка и что она возвратит результат опять таки в каком либо виде.

s> AN>То есть должно быть нечно которому "я дам" аргументы и "могу спросить" ответь ка это верно или нет?

s> Например, у TryGetValue указано, что должен вылетать ArgumentNullException. Это значит что у всех реализаций должно быть так. Пусть на некотором уровне абстракции способ не важен, но мы не сможем ввести абстракцию, не указав конкретный способ для получения информации о корректости аргументов. Конкретный способ тоже может быть абстрактным, но у этой абстракции должен будет быть конкретный интерфейс.

Для чего нам сейчас конкретный интерфейс? Когда можно использовать абстрактный (только в "моем значении"). Если хотите, приведите мне пример конкретного интерфейса и я сделаю из него абстрактный.

s> s>> Нет варианта без исключений. Есть вариант без обработки исключений. Потому как нет такой WriteLine, которая бы не кидала исключений вообще никогда.


s> AN>Держите


s> AN>
WriteLine()
s> AN>{
s> AN>}
s> AN>


s> StackOverflowException вряд ли имеет смысл обрабатывать, но то что он оттуда вылетит при определенных обстоятельствах — это факт.

Описание обстоятельств можно при которых именно "оттуда", а не просто по цепочке стукнуло?

s> s>> Т.е. если командный, то будете склонны изобретать свой метод, вместо использования общеизвестного? Не ясна логика.


s> AN>Я всего лишь сказал, что метод работы будет влиять на выбор, но ничего не говорил о конкретном выборе. Хотя и метод работы не единственное, что будет влиять на выбор. Если допустим, я делаю прогу один, для себя лично, то у меня нет никаких дополнительных ограничивающих факторов, но по мере отклонения от этой линии факторов становится все больше и они могут изменять свой вес.


s> А я всего лишь хотел спросить, влияет ли командная разработка в пользу своих решений вместо традиционных, не известных команде?

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

s> s>> варианты не интересны. Есть что-то неочевидное для соседа. Будет ли алгоритм Дейкстры менее понятен для соседа, чем ваш велосипед?


s> AN>Зависит от ситуации, но вполне возможно что и да. При этом, я не говорю, что мой алгоритм будет лучше. Он может допустим, работать медленней, выжирать память или что еще. Но если плата будет разумной, то я за более понятный вариант.


s> О-как? С учетом "непонятности" Math.Max настораживает.

А что при первом же взгляде на название функции сразу ясно, что она тут может делать? Хотя бы какое то время нужно задержаться и на аргументах.
bufferLength = Math.Max(bufferLength, 0);

Сравните например с этой записью? Какая из двух читабельней?
if (bufferLength < 0)
{
  bufferLength = 0;
}


s> s>> А потом еще 2 дня объяснять команде, чего тут понаписано?


s> AN>А другом случае пусть они сами потратят неделю на понимание, алгоритм то не мой, отчего его объяснять. Сами должны знать...


s> Ваш можно объяснить за 2 дня, а не ваш пусть неделю понимают? Конечно, все пишут такие тупые и непонятные вещи, как Math.Max


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

s> AN>Вообще то из практики: требуется хотя бы полгода работы, для объяснения принципов аж в течении двух дней.

s> AN>


s> Это смотря кому объяснять

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

s> s>> Поясните, будьте добры. Вы его упомянули в ответ на мое предложение подтянуть команду.


s> AN>Ну, можно далеко не ходить за примером "выпендривания"

s> AN>
bufferLength = Math.Max(bufferLength, 0)
s> AN>

s> AN>Изучать нового вроде ничего и нужно, но и понять с первого взгляда, "просмотром кода" не получится.

s> Что тут не понять с первого взгляда? И как написать так, что бы можно было понять с первого взгляда?

см. ответ выше.

s> AN>Это скажем пример "неочевидного использования". Можно еще подумать над примером "необосновано усложненные действия", ну типа вместо трех вызовов конкретных функций сделать цикл по массиву из трех делегатов.


s> Возможно для такого чуда есть повод?

Для этого нужно убрать слово "необоснованное"

s> AN>Вы же имели видимо в виду видимо "неизвестное использование"

s> AN>Ну типа
s> AN>
return await ххх


s> Что за неизвестное использование? Спрашиваем гугль и оно становится известное. А вообще в блогах об этом с пол года пишут.


А если бы вы это год назад увидели? Рассматривайте просто как пример чего то непонятного (без привлечения посторонних источников) За If ведь никто в гугль не лезет.
s> AN>А вот при чем здесь инструменты до меня не дошло.

s> Притом что компилятор, Math.Max, алгоритм Дейкстры, await, исключения и абстракции над WriteLine — это инструменты для решения задач. Мне показалось, что вы принебрегаете одними, довольно простыми, по причинам "сложности", но используете гораздо более сложные...

А чем сложен компилятор? Нажал кнопу и все. Мне даже не нужно знать, что там где то есть какой то ИЛ. Ну и понятие "инструменты" у меня немного иное, но это думаю неважно. Ну а что сложное, что простое — это опять таки тема отдельной бесконечной дискуссии. У каждого может быть свое "верное" мнение.

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


s> AN>Что то я не припоминаю где это я мог упоминать.


s>

s> s> Если манипулирование абстракциями на таком уровне является проблемой для команды, то ну ее нафик, эту абстракцию.

s> Дело не в конкретной проблеме, а в общем подходе. И дело, в основном, упирается во время.

s> s> А может стоит подтянуть команду? Все же это не ахти какой уровень владения программированием.

s> Сегодня она одна, завтра совсем другая. Главный принцип "не выпендриваться".


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

s> s>> но гипертрофированный свитч, по всей видимости, не является проблемой для понимания его работы?


s> AN>Так а что там нужно понимать? Есть выбор и дохрена "комнат".

s> AN>Нужно что новое — добавляешь "комнату" и все.

s> Вот опять, Math.Max непонятно, а 10и-страничный свитч — "что там нужно понимать?"

у данного switch есть "типовой паттерн". Так как все построено в ключе этого паттерна, то завидев этот switch и пару case можно вообще дальше не смотреть. При этом, до этого времени, паттерна можно и не знать, его сразу "видно".
s> AN>Можно было допустим "выпендрится" с атрибутами и забить "комнатки" в функции.
s> AN>Тогда также было бы просто добавить "комнату", но зато общий код получился бы неочевидным, нужно было уже "думать" как, почему и зачем.

s> Мне, например, проще думать чем читать 10 страниц со свитчем или улавливать какие-то закономерности на 10и страницах.

В том то и дело что их ничего не нужно улавливать. Вам кто то объяснял принцип работы топора? Вот это где то в том же духе. Представим работу собаки ищейки, нюхаем, нюхаем, нашли. Вот где то такой грубый принцип исправления неизвестного чужого кода. А этот switch просто воняет, не найти его невозможно, при этом исправить ошибочно нужно еще постараться.
А требование думать — это весьма часто путь к потенциальным ошибкам. Разработчик думал так, вы думаете по другому, я по третьему. Кто может гарантировать что мы все трое будем думать одинаково?
Можно попробовать пофантазировать на тему исправленного switch.
По любому, case будут отделены от выбора, скорее всего в отдельном файле/файлах.
Ладно, имея один файл можно просто вычислить case-ы, но мы хотим также и узнать где находится выбор, простой поиск не помогает, стэк в точке останова не дает ничего о том откуда пришел реальный вызов. Наконец нашли кое как где это выбор вызывается, но почему вызывается именно данная функция так и осталось загадкой. Через какое то время нашли место инициализации, похоже здесь, но функция которая там используется у меня не в голове, нужно лезть в МСДН. Таймер нужно засекать? Сколько времени понадобилось в первый раз и сколько, во второй? Еще думать хочется?
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[5]: Как не надо писать код
От: koandrew Канада http://thingselectronic.blogspot.ca/
Дата: 28.04.11 23:08
Оценка:
Здравствуйте, samius, Вы писали:


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

Угу

S>А на эту тему у меня есть свежий пример из собственной практики. Увидел ворнинг о сравнении знаковых и беззнаковых в следующем коде на C++:

S>
S>for (int i = vector.size() - 1; i >= 0; i--)
S>     foo(vector[i]);
S>

S>исправил на нечто вроде
S>
S>for (size_t i = vector.size() - 1; i >= 0u; i--)
S>     foo(vector[i]);
S>

S>и потом долго не мог связать срыв крыши у программы с этим изменением.
Я таких багов переловил вагон и маленький бронепоезд, да и сам, каюсь, несколько раз попадался — правда в не столь очевидных случаях
[КУ] оккупировала армия.
Re[63]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.04.11 06:19
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> AN>А сколько у вас имплементаций для "хранилища" сервисов?


s>> Обычно не больше одной

AN>Так почему ее нельзя считать глобальной?
Реализацию считать глобальной, потому что нет других реализаций? Вот допустим что существует лишь одна реализация IList<T> — List<T>. Можно ли ее считать глобальной?

s>> Под что именно я пытался уточнить, речь о глобальных состояниях только, или вообще о методах, классах?

AN>Я имел в виду некий объект, доступ к которому может быть необходим из произвольного места кода. Объект может как хранить состояния, так и выполнять некую работу.
AN>Каким образом это будет реализовано, глубоко фиолетово.
Вы же сказали что это будет "глобальная переменная". А это global state, как не реализуй. Так вот, использование глобального хранилища сервисов вряд ли чем-то лучше, чем использование глобальной переменной для каждого сервиса.

AN>Я начинаю подозревать что вы так называемый "практический типаж"

Давайте воздержимся от обсуждения личностей. Хоть ничего оскорбительного я не увидел, но это не по правилам форума.
AN>Метод был взят исключительно для примера глобального метода без исключений как некое противопоставление Console.WriteLine(). А является ли микрософт примером для подражания — это думается, была бы громадная флеймовая ветка.

AN>Для чего нам сейчас конкретный интерфейс? Когда можно использовать абстрактный (только в "моем значении").

Я о том и говорю, что использовать мы его сможем только для абстрактного обсуждения, а при попытке вставить абстракцию в код, без конкретики ничего не выйдет.
AN>Если хотите, приведите мне пример конкретного интерфейса и я сделаю из него абстрактный.
Занятно будет посмотреть
Func<Func<A,B,C>, A, Func<B,C>>


s>> AN>
WriteLine()
s>> AN>{
s>> AN>}
s>> AN>


s>> StackOverflowException вряд ли имеет смысл обрабатывать, но то что он оттуда вылетит при определенных обстоятельствах — это факт.

AN>Описание обстоятельств можно при которых именно "оттуда", а не просто по цепочке стукнуло?
Вы правы, вылетит не именно "оттуда", а при вызове. Как по поводу ThreadAbortException?

s>> А я всего лишь хотел спросить, влияет ли командная разработка в пользу своих решений вместо традиционных, не известных команде?

AN>...
AN>Если задача подразумевает вероятное "академическое решение", то лучше вначале использовать его.
Так вот, вернувшись к выделению абстракции над WriteLine, это и есть вероятное "академическое решение".

AN>А что при первом же взгляде на название функции сразу ясно, что она тут может делать? Хотя бы какое то время нужно задержаться и на аргументах.

AN>
bufferLength = Math.Max(bufferLength, 0);

AN>Сравните например с этой записью? Какая из двух читабельней?
AN>
if (bufferLength < 0)
AN>{
AN>  bufferLength = 0;
AN>}

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

AN>Обычно объяснять нужно гораздо меньше чем разбираться самому (может быть и наоборот, но это скорее исключение, чем правило) И свое объяснять проще чем чужое.

Это субъективное наблюдение

s>> Это смотря кому объяснять

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

s>> Что за неизвестное использование? Спрашиваем гугль и оно становится известное. А вообще в блогах об этом с пол года пишут.


AN>А если бы вы это год назад увидели? Рассматривайте просто как пример чего то непонятного (без привлечения посторонних источников) За If ведь никто в гугль не лезет.

Использование неочевидных конструкций подразумевает (но не гарантирует) то что использование очевидных конструкций чем-то не устраивает. По поводу того же await — мне будет проще почитать в паре-тройке мест, что он значит и потом понимать его в 20и местах использования, чем в 20 местах вчитываться в нагромождение очевидных конструкций.

AN>А чем сложен компилятор? Нажал кнопу и все. Мне даже не нужно знать, что там где то есть какой то ИЛ. Ну и понятие "инструменты" у меня немного иное, но это думаю неважно. Ну а что сложное, что простое — это опять таки тема отдельной бесконечной дискуссии. У каждого может быть свое "верное" мнение.

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

AN>так и не доходит почему это у вас все так связалось. Видимо вы имели в виду "это конкретное", а я нечно "абстрактное".

Мы обсуждали то, будет ли понятно введение абстракции для команды.

s>> Вот опять, Math.Max непонятно, а 10и-страничный свитч — "что там нужно понимать?"

AN>у данного switch есть "типовой паттерн". Так как все построено в ключе этого паттерна, то завидев этот switch и пару case можно вообще дальше не смотреть. При этом, до этого времени, паттерна можно и не знать, его сразу "видно".
Я-то его не видел. Я просто реагирую на "10и страничный свитч" и представляю себе такого нормального монстрика с вложенными свитчами, goto и всякой прелестью, что является вполне типично для 2х и более страничных свитчей, выходящих из под топора среднеотраслевых мастеров.

AN>А требование думать — это весьма часто путь к потенциальным ошибкам. Разработчик думал так, вы думаете по другому, я по третьему. Кто может гарантировать что мы все трое будем думать одинаково?

Думать можно разными путями, а уж недумая —
AN>Можно попробовать пофантазировать на тему исправленного switch.
AN>По любому, case будут отделены от выбора, скорее всего в отдельном файле/файлах.
AN>Ладно, имея один файл можно просто вычислить case-ы, но мы хотим также и узнать где находится выбор, простой поиск не помогает, стэк в точке останова не дает ничего о том откуда пришел реальный вызов. Наконец нашли кое как где это выбор вызывается, но почему вызывается именно данная функция так и осталось загадкой. Через какое то время нашли место инициализации, похоже здесь, но функция которая там используется у меня не в голове, нужно лезть в МСДН. Таймер нужно засекать? Сколько времени понадобилось в первый раз и сколько, во второй? Еще думать хочется?
Мне кажется что у нас с вами разные отладчики. Не приходилось сталкиваться с описанными проблемами. И стек мне видно и Step Into входит в куда надо и брекпоинты ставятся, и место инициализации находится хоть средой хоть рефлектором за секунды. Такое ощущение, что вы отлаживаетесь по твердой копии исходников...
Re[6]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.04.11 06:25
Оценка:
Здравствуйте, koandrew, Вы писали:

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


S>>и потом долго не мог связать срыв крыши у программы с этим изменением.

K>Я таких багов переловил вагон и маленький бронепоезд, да и сам, каюсь, несколько раз попадался — правда в не столь очевидных случаях
Да я тоже их когда-то ловил, до перехода на C#. А потом за 8 лет привык к хорошему. В том числе что проверка диапазона часто позволяет определять такие баги на ранней стадии. Здесь же глядя на мусор в результате пришлось локализовывать баг самому. Не помню что мешало переключиться в DEBUG... Видимо не предполагал что ошибка связана с выходом из диапазона.
Re[3]: Как не надо писать код
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 29.04.11 08:57
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>А откуда появилась информация об обрезании?

AN>И что именно проверяется перед началом?
AN>Какие действия предпринимаются для неправильных данных? Верны они или нет?
AN>Вопросов можно еще найти довольно много и ответ во многих случаях нужно искать, а не "увидеть"

Обрезание из пределов цикла. В начале всякие проверки на null и Length = 0. Вообще, когда тебе попадается такой код, то есть еще и некоторая предметная область.

Я не говорю, что код написал идеально, я просто написал то, что увидел за 10 секунд просмотра.
Re[64]: Как не надо писать код
От: AlexNek  
Дата: 29.04.11 14:19
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> AN>А сколько у вас имплементаций для "хранилища" сервисов?


s> s>> Обычно не больше одной


s> AN>Так почему ее нельзя считать глобальной?


s> Реализацию считать глобальной, потому что нет других реализаций? Вот допустим что существует лишь одна реализация IList<T> — List<T>. Можно ли ее считать глобальной?

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

s> s>> Под что именно я пытался уточнить, речь о глобальных состояниях только, или вообще о методах, классах?


s> AN>Я имел в виду некий объект, доступ к которому может быть необходим из произвольного места кода. Объект может как хранить состояния, так и выполнять некую работу.

s> AN>Каким образом это будет реализовано, глубоко фиолетово.

s> Вы же сказали что это будет "глобальная переменная". А это global state, как не реализуй.

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

s> Так вот, использование глобального хранилища сервисов вряд ли чем-то лучше, чем использование глобальной переменной для каждого сервиса.

Видимо под словом "глобальный" мы подразумеваем различные вещи.

s> AN>Я начинаю подозревать что вы так называемый "практический типаж"


s> Давайте воздержимся от обсуждения личностей. Хоть ничего оскорбительного я не увидел, но это не по правилам форума.

Я вроде и не собирался этого делать, думаю из контекста было понятно, что я всего лишь рассуждал в каком ключе было бы удобнее вести с Вами беседу. Если вы расценили это как покушение на "privacy", то могу попросить прощения.
Надеюсь, вы не будет отрицать, что нельзя в одинаковом "ключе" говорить со всеми.
Если у нас, большая разница в "способе мышления", то мои высказывания будут непонятны Вам, а мне Ваши. Поэтому я обычно стараюсь подстраивать высказывания под способ мышления "собеседника", А его высказывания "переводить" на свой.

s> AN>Метод был взят исключительно для примера глобального метода без исключений как некое противопоставление Console.WriteLine(). А является ли микрософт примером для подражания — это думается, была бы громадная флеймовая ветка.


s> AN>Для чего нам сейчас конкретный интерфейс? Когда можно использовать абстрактный (только в "моем значении").


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

Если нам понадобится вставлять в код, тогда можно и обговорить конкретику.

s> AN>Если хотите, приведите мне пример конкретного интерфейса и я сделаю из него абстрактный.


s> Занятно будет посмотреть

s>
s> Func<Func<A,B,C>, A, Func<B,C>>
s>

Вот подобные вещи и можно назвать "выпендриванием", напомнило старый анекдот про японскую деревообрабатывающую машину и стальное бревно. Подразумевалось как бы "в контексте обсуждаемой темы". Хотя в абстрактном виде это видимо выглядело бы так:
"Сделай что то зависящее от A,B,C". Хотя мне и весьма проблематично представить данную строку в описании интерфейса.

s> s>> AN>
WriteLine()
s> s>> AN>{
s> s>> AN>}
s> s>> AN>


s> s>> StackOverflowException вряд ли имеет смысл обрабатывать, но то что он оттуда вылетит при определенных обстоятельствах — это факт.


s> AN>Описание обстоятельств можно при которых именно "оттуда", а не просто по цепочке стукнуло?


s> Вы правы, вылетит не именно "оттуда", а при вызове. Как по поводу ThreadAbortException?

А оно специфично именно для этой функции? В описании "Console.WriteLine" оно также упомянуто? Мы обсуждаем работу многопотоковых приложений?

s> s>> А я всего лишь хотел спросить, влияет ли командная разработка в пользу своих решений вместо традиционных, не известных команде?


s> AN>...

s> AN>Если задача подразумевает вероятное "академическое решение", то лучше вначале использовать его.

s> Так вот, вернувшись к выделению абстракции над WriteLine, это и есть вероятное "академическое решение".

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

s> AN>А что при первом же взгляде на название функции сразу ясно, что она тут может делать? Хотя бы какое то время нужно задержаться и на аргументах.

s> AN>
bufferLength = Math.Max(bufferLength, 0);

s> AN>Сравните например с этой записью? Какая из двух читабельней?
s> AN>
if (bufferLength < 0)
s> AN>{
s> AN>  bufferLength = 0;
s> AN>}


s> Безусловно первая. Задерживаюсь на аргументах: в ней меньшая цикломатическая сложность, меньше магических чисел, меньше вероятность ошибиться, проще тестировать.

Думаю, какая либо дискуссия тут бесполезна, возможно только статистика бы помогла. Могу только попробовать высказать мои соображения.
— 1. Ассоциативное мышление. Я ожидаю увидеть функцию Math.Max в определенном контексте при выборе из двух "одинаковых сущностей". У меня есть еще второй буфер и нужно найти длина которого из них больше? Нет, есть переменная и константа 0. А нафига из них выбирать наибольшее? Ага, имеет смысл только если переменная меньше нуля. Пусть и небольшие, но все же раздумья.
— 2. "Визуальное восприятие паттернов". (мое "личное" определение, только что придумал ) Когда я смотрю на первый пример я вижу "х = функция от у", когда я вижу
второй то "х=0". Т.е для первого нужно пройти часть пути "ассоциативное мышление".
Во втором сразу видно три хорошо знакомых "паттерна" (if, х<0, x=0), которые можно сразу же прочитать даже на разговорном языке.
— 3. "Примитивизм" — перекликается с 2. Используются настолько простые конструкции, что даже человек не знающий программирования может их понять. А знающий поймет с "закрытыми глазами". В первом же случае нужно знать, что делает функция Max, какие у нее аргументы, почему именно такие аргументы.

s> Первая запись является выражением и может быть использована в других выражениях, в то время как вторая — нет.

Для меня это не достоинство, а громадный недостаток. Есл потребует то лучше сделать что то типа GetNormalizedBufferLength(int x)

s> AN>Обычно объяснять нужно гораздо меньше чем разбираться самому (может быть и наоборот, но это скорее исключение, чем правило) И свое объяснять проще чем чужое.


s> Это субъективное наблюдение

Я не проводил научных исследований, но мне лично обратное еще не встречалось.

s> s>> Это смотря кому объяснять


s> AN>Для недотеп может и не хватить двух . Но мы ведь на среднюю температуру по больнице ориентируемся. Новый принцип работы трясины все равно кому объяснять, если все из одного болота. Но есть время выдачи основной массы информации, как и способ ее подачи. Ну и сами знаете сколько килограмм продукта нужно для получения килограмма варенья.


s> Случай, когда объяснятель и объясняемый близки к средней температуре по больнице, не интересен. Они друг дружке что-то принципиально новое вряд ли объяснят.

Ну отчего же? Вы разрабатывали подсистему А, я подсистему Б. Объяснения друг другу будут весьма полезны. А объяснять работу подсистемы А дежурному сантехнику не будет иметь большого смысла.

s> s>> Что за неизвестное использование? Спрашиваем гугль и оно становится известное. А вообще в блогах об этом с пол года пишут.


s> AN>А если бы вы это год назад увидели? Рассматривайте просто как пример чего то непонятного (без привлечения посторонних источников) За If ведь никто в гугль не лезет.


s> Использование неочевидных конструкций подразумевает (но не гарантирует) то что использование очевидных конструкций чем-то не устраивает.

Конечно

s> По поводу того же await — мне будет проще почитать в паре-тройке мест, что он значит и потом понимать его в 20и местах использования, чем в 20 местах вчитываться в нагромождение очевидных конструкций.

Я привел только пример, что было понятно, что я имею в виду. Но с другой стороны, эти 20 мест уже могут жить в коде лет этак 5 и каждый знает их почти наизусть.
Как я уже говорил, конкретная ситуация может быть самая разная. Да и включение чего
то нового должно быть "официально одобрено". Если "я нашел" этот await вчера, то это не значит, что я его имею право его использовать уже завтра сразу в проекте.

s> AN>А чем сложен компилятор? Нажал кнопу и все. Мне даже не нужно знать, что там где то есть какой то ИЛ. Ну и понятие "инструменты" у меня немного иное, но это думаю неважно. Ну а что сложное, что простое — это опять таки тема отдельной бесконечной дискуссии. У каждого может быть свое "верное" мнение.


s> Компилятор достаточно сложен, просто лишь его использование в духе "нажал кнопку". Однако использование не подразумевает понимания процессов, происходящих в конкретном компиляторе. В то время как понимать процессы, происходящие при выделении абстракции, вполне доступно для программиста уровня джуниора.

Тут видимо опять какое то различие в толкованиях.

s> AN>так и не доходит почему это у вас все так связалось. Видимо вы имели в виду "это конкретное", а я нечно "абстрактное".


s> Мы обсуждали то, будет ли понятно введение абстракции для команды.


s> s>> Вот опять, Math.Max непонятно, а 10и-страничный свитч — "что там нужно понимать?"


s> AN>у данного switch есть "типовой паттерн". Так как все построено в ключе этого паттерна, то завидев этот switch и пару case можно вообще дальше не смотреть. При этом, до этого времени, паттерна можно и не знать, его сразу "видно".


s> Я-то его не видел. Я просто реагирую на "10и страничный свитч" и представляю себе такого нормального монстрика с вложенными свитчами, goto и всякой прелестью, что является вполне типично для 2х и более страничных свитчей, выходящих из под топора среднеотраслевых мастеров.

Видите, а мне описанный Вами свитч тяжело представить
Еще не встречал фирмы где goto был бы разрешен.

s> AN>А требование думать — это весьма часто путь к потенциальным ошибкам. Разработчик думал так, вы думаете по другому, я по третьему. Кто может гарантировать что мы все трое будем думать одинаково?


s> Думать можно разными путями, а уж недумая —

Это довольно просто.
Предположим, я или скажу
"В темной темнице красны девицы.
Без нитки, без спицы вяжут вязеницы"
или просто покажу картинку.
Что быстрее доведет до цели, о чем это я?

s> AN>Можно попробовать пофантазировать на тему исправленного switch.

s> AN>По любому, case будут отделены от выбора, скорее всего в отдельном файле/файлах.
s> AN>Ладно, имея один файл можно просто вычислить case-ы, но мы хотим также и узнать где находится выбор, простой поиск не помогает, стэк в точке останова не дает ничего о том откуда пришел реальный вызов. Наконец нашли кое как где это выбор вызывается, но почему вызывается именно данная функция так и осталось загадкой. Через какое то время нашли место инициализации, похоже здесь, но функция которая там используется у меня не в голове, нужно лезть в МСДН. Таймер нужно засекать? Сколько времени понадобилось в первый раз и сколько, во второй? Еще думать хочется?

s> Мне кажется что у нас с вами разные отладчики. Не приходилось сталкиваться с описанными проблемами. И стек мне видно и Step Into входит в куда надо и брекпоинты ставятся, и место инициализации находится хоть средой хоть рефлектором за секунды. Такое ощущение, что вы отлаживаетесь по твердой копии исходников...

Я думаю, что мы просто разные проекты делаем. Вот например, примерчик из здешнего проекта Janus, найдите любым из перечисленных вами способов откуда вызывается данная функция

[MethodShortcut(Shortcut.CtrlP, "Создать раздел", "Создать раздел")]
private void AddFolder()
{
    _serviceManager.TryExecuteCommand("Favorites.Commands.CreateFolder.DisplayName", new Dictionary<string, object>());
}

Теперь поставьте точку останова на функцию AddFolder и покажите на стеке вызов из ProcessMessageKey, да, и потом поставьте уже на данной строке точку останова и при помощи Step Into зайдите в функцию AddFolder.
             
ProcessMessageKey()
{
...
  methodInfo.Invoke(target, null);
}


Просто как некоторый пример, о чем я вёл речь.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[4]: Как не надо писать код
От: AlexNek  
Дата: 29.04.11 14:20
Оценка:
Здравствуйте, Mystic, Вы писали:

M> AN>А откуда появилась информация об обрезании?

M> AN>И что именно проверяется перед началом?
M> AN>Какие действия предпринимаются для неправильных данных? Верны они или нет?
M> AN>Вопросов можно еще найти довольно много и ответ во многих случаях нужно искать, а не "увидеть"

M> Обрезание из пределов цикла.

Как говорится, "не верь глазам своим". Там далеко сверху есть еще +1.
M> В начале всякие проверки на null и Length = 0. Вообще, когда тебе попадается такой код, то есть еще и некоторая предметная область.
В том и дело, что такой код. Не должен такой код попадаться на глаза.
И для подобной задачи, не требуется знать предметной области. Задача следующая:
есть некий байтовый буфер, который допустимо изменять. Требуется добавить в его начало специальный символ, при ошибках входных данных желательно выдавать "нулевую комбинацию", а не прерывать выполнение.

M> Я не говорю, что код написал идеально, я просто написал то, что увидел за 10 секунд просмотра.

Код написан просто катастрофически, а вот если бы код был написан хотя бы нормально, то за эти 10 секунд можно было увидеть и понять гораздо больше. Именно это мне и хотелось показать — "Народ, давайте не будет писать подобный код".
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[65]: Как не надо писать код
От: samius Япония http://sams-tricks.blogspot.com
Дата: 29.04.11 19:25
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


s>> Реализацию считать глобальной, потому что нет других реализаций? Вот допустим что существует лишь одна реализация IList<T> — List<T>. Можно ли ее считать глобальной?

AN>Если она используется локально, то нет. А когда речь идет о доступности с любого места кода, то я пока не могу найти отличий.
Обычно под реализацией/имплементацией подразумевают типы, а не экземпляры. Доступность типа в дотнете определяется не количеством, а модификатороми видимости для него и типов, в которые он вложен. Т.е. непонятно что вы подразумеваете под применением термина глобальность к типу(реализации/имплементации).
Все зкземпляры глобальны в рамках процесса. Т.е. имея его ардес/ссылку на экземпляр, не составит труда обратиться к нему отовсюду.

s>> Вы же сказали что это будет "глобальная переменная". А это global state, как не реализуй.

AN>Можно списать на "ошибки" вербальной коммуникации, я подразумевал под этим несколько другое.
И все-таки непонятно, что именно.

s>> Так вот, использование глобального хранилища сервисов вряд ли чем-то лучше, чем использование глобальной переменной для каждого сервиса.

AN>Видимо под словом "глобальный" мы подразумеваем различные вещи.
Может ссылку дадите?

s>> Давайте воздержимся от обсуждения личностей. Хоть ничего оскорбительного я не увидел, но это не по правилам форума.

AN>Я вроде и не собирался этого делать, думаю из контекста было понятно, что я всего лишь рассуждал в каком ключе было бы удобнее вести с Вами беседу. Если вы расценили это как покушение на "privacy", то могу попросить прощения.
Нет, обижаться в данном случае не на что. Просто это запрещено правилами.
AN>Надеюсь, вы не будет отрицать, что нельзя в одинаковом "ключе" говорить со всеми.
нет, не буду
AN>Если у нас, большая разница в "способе мышления", то мои высказывания будут непонятны Вам, а мне Ваши. Поэтому я обычно стараюсь подстраивать высказывания под способ мышления "собеседника", А его высказывания "переводить" на свой.
У нас еще разница в терминологии

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

AN>Если нам понадобится вставлять в код, тогда можно и обговорить конкретику.
Именно так

s>> AN>Если хотите, приведите мне пример конкретного интерфейса и я сделаю из него абстрактный.


s>> Занятно будет посмотреть

s>>
s>> Func<Func<A,B,C>, A, Func<B,C>>
s>>

AN>Вот подобные вещи и можно назвать "выпендриванием", напомнило старый анекдот про японскую деревообрабатывающую машину и стальное бревно. Подразумевалось как бы "в контексте обсуждаемой темы". Хотя в абстрактном виде это видимо выглядело бы так:
AN>"Сделай что то зависящее от A,B,C". Хотя мне и весьма проблематично представить данную строку в описании интерфейса.
Это фактически и есть интерфейс метода, выполняющего эмуляцию частичного применения функции. Реализация функции занимает одну строчку, делает она вещи, которые не зависят от A, B и тем более C. Этот милый прием позволил мне не писать порядка двухсот классов в текущем проекте.
В описании интерфейса это могло бы выглядеть так:
interface IFoo
{
    Func<B, C> Apply<A, B, C>(Func<A, B, C> func, A a);
}

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

s>> AN>Описание обстоятельств можно при которых именно "оттуда", а не просто по цепочке стукнуло?


s>> Вы правы, вылетит не именно "оттуда", а при вызове. Как по поводу ThreadAbortException?

AN>А оно специфично именно для этой функции? В описании "Console.WriteLine" оно также упомянуто? Мы обсуждаем работу многопотоковых приложений?
Да, специфично. Нет, не упомянуто. В "однопотоковом" оно тоже может вылететь. И я даже как-то не уверен, можно ли на .net написать "однопотоковое" приложение. Можно не запускать никаких вспомогательных потоков явно, но это не значит что их не будет .

s>> Так вот, вернувшись к выделению абстракции над WriteLine, это и есть вероятное "академическое решение".

AN>Вообще то имелись в виду различные математические алгоритмы. Но даже и в данном случае это было бы "неоправданным усложнением".
Предложите другой вариант, кроме как забивание на факт существования исключений. Напомню, что WriteLine взята лишь для примера, и вместо нее может быть любая другая функция. Мы говорим о концепте, не так ли?

s>> Безусловно первая. Задерживаюсь на аргументах: в ней меньшая цикломатическая сложность, меньше магических чисел, меньше вероятность ошибиться, проще тестировать.

AN>Думаю, какая либо дискуссия тут бесполезна, возможно только статистика бы помогла. Могу только попробовать высказать мои соображения.
AN>- 1. Ассоциативное мышление. Я ожидаю увидеть функцию Math.Max в определенном контексте при выборе из двух "одинаковых сущностей". У меня есть еще второй буфер и нужно найти длина которого из них больше? Нет, есть переменная и константа 0. А нафига из них выбирать наибольшее? Ага, имеет смысл только если переменная меньше нуля. Пусть и небольшие, но все же раздумья.
я не понял, т.е. если бы там стояло 100 вместо 0-я, то ничего бы не смущало?
AN>- 2. "Визуальное восприятие паттернов". (мое "личное" определение, только что придумал ) Когда я смотрю на первый пример я вижу "х = функция от у", когда я вижу
AN>второй то "х=0". Т.е для первого нужно пройти часть пути "ассоциативное мышление".
AN>Во втором сразу видно три хорошо знакомых "паттерна" (if, х<0, x=0), которые можно сразу же прочитать даже на разговорном языке.
(if, x<0, y=10) — тоже можно прочитать на разговорном языке, только здесь два небольших отличия, меняющих смысл кардинально. Но что самое интересное, (max, x, 0) — тоже легко читается.
AN>- 3. "Примитивизм" — перекликается с 2. Используются настолько простые конструкции, что даже человек не знающий программирования может их понять. А знающий поймет с "закрытыми глазами". В первом же случае нужно знать, что делает функция Max, какие у нее аргументы, почему именно такие аргументы.
Давайте теперь прикинием, что же нам больше знеакомо, max или if по жизни? Пример: нужно взять самое большое/красное яблоко из 5и штук, отбросив всякую скромность и деликатность. Любой ребенок выберет его бессознательно, не сравнивая при этом каждое с каждым и не оперируя if-ами. А к if-ам вы привыкли, видимо уже в разговоре с компьютером. И так хорошо привыкли, что более высокий уровень общения с компьютером у вас вызывает дискомфорт.
Заменяете ли вы if-ами виртуальные вызовы? Если нет, то что вы слышали о виртуальных вызовах до знакомства с программированием?

s>> Первая запись является выражением и может быть использована в других выражениях, в то время как вторая — нет.

AN>Для меня это не достоинство, а громадный недостаток. Есл потребует то лучше сделать что то типа GetNormalizedBufferLength(int x)
Хороший позыв. Но если заменить в тех примерах bufferLenght на x, то смысл функции GetNormalizedBufferLength будет ускользать. Ну и не будете же вы для каждого if-а плодить GetSomething(x)? Мне тут лично max кажется более уместным, т.к. что делает max мы можем догадаться, а что подразумевается под NormalizedBufferLength — тут нужны экстрасенсы. Так, если привести постороннего человека, то вряд ли он угадает что под нормализованной длиной буфера подразумевается неотрицательная.
Кстати, получение отрицательной длины буфера — это логическая ошибка в программе, которую надо исправлять как можно скорее, а не прятать ее. Но я уже писал об этом. Отрицательная длина не может считаться ненормальной, т.к. отрицательная длина — есть катастрофическая длина.

s>> Это субъективное наблюдение

AN>Я не проводил научных исследований, но мне лично обратное еще не встречалось.
Мне встречалось.

s>> Случай, когда объяснятель и объясняемый близки к средней температуре по больнице, не интересен. Они друг дружке что-то принципиально новое вряд ли объяснят.

AN>Ну отчего же? Вы разрабатывали подсистему А, я подсистему Б. Объяснения друг другу будут весьма полезны. А объяснять работу подсистемы А дежурному сантехнику не будет иметь большого смысла.
Вы не пытались объяснить смысл алгоритма Дейкстры (например) программисту, совершенно незнакомому с теорией графов?

s>> По поводу того же await — мне будет проще почитать в паре-тройке мест, что он значит и потом понимать его в 20и местах использования, чем в 20 местах вчитываться в нагромождение очевидных конструкций.

AN>Я привел только пример, что было понятно, что я имею в виду. Но с другой стороны, эти 20 мест уже могут жить в коде лет этак 5 и каждый знает их почти наизусть.
AN>Как я уже говорил, конкретная ситуация может быть самая разная. Да и включение чего
AN>то нового должно быть "официально одобрено". Если "я нашел" этот await вчера, то это не значит, что я его имею право его использовать уже завтра сразу в проекте.
ну фиг с ним с await. Некоторые до сих пор находят для себя yield return. Значит ли это что его нельзя использовать сразу в проекте? И у вас что, есть перечень конструкций, которые можно/нельзя использовать в проекте?
У меня есть обратный пример, когда проект был скован .net 2.0 спустя пару лет после выхода 3.5. Когда я протащил в проект linq (сваял аналог linqbridge), команда сначала отнеслась без этнузиазма, но спустя пару недель начали продуктивно применять.

s>> Я-то его не видел. Я просто реагирую на "10и страничный свитч" и представляю себе такого нормального монстрика с вложенными свитчами, goto и всякой прелестью, что является вполне типично для 2х и более страничных свитчей, выходящих из под топора среднеотраслевых мастеров.

AN>Видите, а мне описанный Вами свитч тяжело представить
AN>Еще не встречал фирмы где goto был бы разрешен.
А я 8 лет проработал в конторе, где его до сих пор предпочитают другим способам переходов.

s>> Думать можно разными путями, а уж недумая —

AN>Это довольно просто.
AN>Предположим, я или скажу
AN>"В темной темнице красны девицы.
AN>Без нитки, без спицы вяжут вязеницы"
AN>или просто покажу картинку.
AN>Что быстрее доведет до цели, о чем это я?


s>> Мне кажется что у нас с вами разные отладчики. Не приходилось сталкиваться с описанными проблемами. И стек мне видно и Step Into входит в куда надо и брекпоинты ставятся, и место инициализации находится хоть средой хоть рефлектором за секунды. Такое ощущение, что вы отлаживаетесь по твердой копии исходников...

AN>Я думаю, что мы просто разные проекты делаем. Вот например, примерчик из здешнего проекта Janus, найдите любым из перечисленных вами способов откуда вызывается данная функция
Если честно — лень даже скачивать.

AN>Теперь поставьте точку останова на функцию AddFolder и покажите на стеке вызов из ProcessMessageKey, да, и потом поставьте уже на данной строке точку останова и при помощи Step Into зайдите в функцию AddFolder.

AN>
             
AN>  methodInfo.Invoke(target, null);
AN>

AN>Просто как некоторый пример, о чем я вёл речь.
На сколько я понимаю в этих корках от апельсинов — проблема вовсе не в выпендреже, а в вызове через MethodInfo.Invoke. Если создать Action из methodInfo, а потом вызвать его, то будет и стек и StepInto, и девченки.
Re[66]: Как не надо писать код
От: AlexNek  
Дата: 30.04.11 14:47
Оценка:
Здравствуйте, samius, Вы писали:

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


s> s>> Реализацию считать глобальной, потому что нет других реализаций? Вот допустим что существует лишь одна реализация IList<T> — List<T>. Можно ли ее считать глобальной?


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


s> Обычно под реализацией/имплементацией подразумевают типы, а не экземпляры.

Тогда скажите как перевести например Data Type Implementation?
Вы видимо имеете в виду Interface Implementation?
s> Доступность типа в дотнете определяется не количеством, а модификатороми видимости для него и типов, в которые он вложен. Т.е. непонятно что вы подразумеваете под применением термина глобальность к типу(реализации/имплементации).
Он подразумевается не к типу.

s> Все зкземпляры глобальны в рамках процесса. Т.е. имея его ардес/ссылку на экземпляр, не составит труда обратиться к нему отовсюду.

И откуда нам знать этот адрес или ссылку? И кстати, где то об этой глобальности и идет речь.
Как например обратится к A1, A2?
void f()
{
  int A1=0;
}

public class X
{
   public int A2 = 0;
}

s> s>> Вы же сказали что это будет "глобальная переменная". А это global state, как не реализуй.

s> AN>Можно списать на "ошибки" вербальной коммуникации, я подразумевал под этим несколько другое.


s> И все-таки непонятно, что именно.

Могу привести некоторые примеры глобального: static и singleton
Console.WriteLine();
A.VariableX;
A.GetInstance();

s> s>> Так вот, использование глобального хранилища сервисов вряд ли чем-то лучше, чем использование глобальной переменной для каждого сервиса.


s> AN>Видимо под словом "глобальный" мы подразумеваем различные вещи.


s> Может ссылку дадите?

Не имею понятия на что именно.
s> s>> Давайте воздержимся от обсуждения личностей. Хоть ничего оскорбительного я не увидел, но это не по правилам форума.

s> AN>Я вроде и не собирался этого делать, думаю из контекста было понятно, что я всего лишь рассуждал в каком ключе было бы удобнее вести с Вами беседу. Если вы расценили это как покушение на "privacy", то могу попросить прощения.


s> Нет, обижаться в данном случае не на что. Просто это запрещено правилами.

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

s> AN>Надеюсь, вы не будет отрицать, что нельзя в одинаковом "ключе" говорить со всеми.


s> нет, не буду

Тогда как узнать в каком ключе нужно говорить с человеком? Можно конечно действовать методом проб и ошибок, а можно и просто каким то образом спросить.
s> AN>Если у нас, большая разница в "способе мышления", то мои высказывания будут непонятны Вам, а мне Ваши. Поэтому я обычно стараюсь подстраивать высказывания под способ мышления "собеседника", А его высказывания "переводить" на свой.

s> У нас еще разница в терминологии

Я это тоже заметил Просто мы находимся в различных средах.
s> s>> Я о том и говорю, что использовать мы его сможем только для абстрактного обсуждения, а при попытке вставить абстракцию в код, без конкретики ничего не выйдет.

s> AN>Если нам понадобится вставлять в код, тогда можно и обговорить конкретику.


s> Именно так


s> s>> AN>Если хотите, приведите мне пример конкретного интерфейса и я сделаю из него абстрактный.


s> s>> Занятно будет посмотреть

s> s>>
s> s>> Func<Func<A,B,C>, A, Func<B,C>>
s> s>>


s> AN>Вот подобные вещи и можно назвать "выпендриванием", напомнило старый анекдот про японскую деревообрабатывающую машину и стальное бревно. Подразумевалось как бы "в контексте обсуждаемой темы". Хотя в абстрактном виде это видимо выглядело бы так:

s> AN>"Сделай что то зависящее от A,B,C". Хотя мне и весьма проблематично представить данную строку в описании интерфейса.

s> Это фактически и есть интерфейс метода, выполняющего эмуляцию частичного применения функции. Реализация функции занимает одну строчку, делает она вещи, которые не зависят от A, B и тем более C.

Ну это если придерживаться точки зрения что List<T> не зависит от T.
А если он от него не зависит, то его вполне можно убрать, но убрать то мы его не можем, значит какая то зависимость все же есть?
s> Этот милый прием позволил мне не писать порядка двухсот классов в текущем проекте.
Мне пока сложно представить такую экономию, но я бы предпочел чего попроще, может с не такой большой экономией.

s> В описании интерфейса это могло бы выглядеть так:

s>
s> interface IFoo
s> {
s>     Func<B, C> Apply<A, B, C>(Func<A, B, C> func, A a);
s> }
s>

s> Но сам метод не нуждается в таком интерфейсе, т.к. подменять его особо незачем.

s> s>> AN>Описание обстоятельств можно при которых именно "оттуда", а не просто по цепочке стукнуло?


s> s>> Вы правы, вылетит не именно "оттуда", а при вызове. Как по поводу ThreadAbortException?


s> AN>А оно специфично именно для этой функции? В описании "Console.WriteLine" оно также упомянуто? Мы обсуждаем работу многопотоковых приложений?


s> Да, специфично.

каким образом? Только из-за того что попало "под горячую руку".
s> Нет, не упомянуто.
s> В "однопотоковом" оно тоже может вылететь.
Вот так, просто само по себе?. И что будет являться инициатором?
s> И я даже как-то не уверен, можно ли на .net написать "однопотоковое" приложение. Можно не запускать никаких вспомогательных потоков явно, но это не значит что их не будет .
Про это вроде разговора не было.

s> s>> Так вот, вернувшись к выделению абстракции над WriteLine, это и есть вероятное "академическое решение".


s> AN>Вообще то имелись в виду различные математические алгоритмы. Но даже и в данном случае это было бы "неоправданным усложнением".


s> Предложите другой вариант, кроме как забивание на факт существования исключений. Напомню, что WriteLine взята лишь для примера, и вместо нее может быть любая другая функция. Мы говорим о концепте, не так ли?

Да, о двух разных подходах.

s> s>> Безусловно первая. Задерживаюсь на аргументах: в ней меньшая цикломатическая сложность, меньше магических чисел, меньше вероятность ошибиться, проще тестировать.


s> AN>Думаю, какая либо дискуссия тут бесполезна, возможно только статистика бы помогла. Могу только попробовать высказать мои соображения.

s> AN>- 1. Ассоциативное мышление. Я ожидаю увидеть функцию Math.Max в определенном контексте при выборе из двух "одинаковых сущностей". У меня есть еще второй буфер и нужно найти длина которого из них больше? Нет, есть переменная и константа 0. А нафига из них выбирать наибольшее? Ага, имеет смысл только если переменная меньше нуля. Пусть и небольшие, но все же раздумья.

s> я не понял, т.е. если бы там стояло 100 вместо 0-я, то ничего бы не смущало?

Не смущало, если бы там стояло bufferLength2.

s> AN>- 2. "Визуальное восприятие паттернов". (мое "личное" определение, только что придумал ) Когда я смотрю на первый пример я вижу "х = функция от у", когда я вижу

s> AN>второй то "х=0". Т.е для первого нужно пройти часть пути "ассоциативное мышление".
s> AN>Во втором сразу видно три хорошо знакомых "паттерна" (if, х<0, x=0), которые можно сразу же прочитать даже на разговорном языке.

s> (if, x<0, y=10) — тоже можно прочитать на разговорном языке, только здесь два небольших отличия, меняющих смысл кардинально. Но что самое интересное, (max, x, 0) — тоже легко читается.

И что будет понятно немедленно после прочтения, а также и во время?
"Найдем максимум из двух чисел: Х и 0"
Сравните
"Если Х меньше нуля то сделать его равным нулю" — не нужно ничего не думать ни пояснять, уже во время чтения мы получаем четкие команды.

s> AN>- 3. "Примитивизм" — перекликается с 2. Используются настолько простые конструкции, что даже человек не знающий программирования может их понять. А знающий поймет с "закрытыми глазами". В первом же случае нужно знать, что делает функция Max, какие у нее аргументы, почему именно такие аргументы.


s> Давайте теперь прикинием, что же нам больше знеакомо, max или if по жизни? Пример: нужно взять самое большое/красное яблоко из 5и штук, отбросив всякую скромность и деликатность.

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

s> Любой ребенок выберет его бессознательно, не сравнивая при этом каждое с каждым и не оперируя if-ами. А к if-ам вы привыкли, видимо уже в разговоре с компьютером. И так хорошо привыкли, что более высокий уровень общения с компьютером у вас вызывает дискомфорт.

Дело не только в привычке. Вот вы пришли в кино зал, что вы там ожидаете увидеть?
s> Заменяете ли вы if-ами виртуальные вызовы? Если нет, то что вы слышали о виртуальных вызовах до знакомства с программированием?
Не понятно к чему вы клоните.

s> s>> Первая запись является выражением и может быть использована в других выражениях, в то время как вторая — нет.


s> AN>Для меня это не достоинство, а громадный недостаток. Есл потребует то лучше сделать что то типа GetNormalizedBufferLength(int x)


s> Хороший позыв. Но если заменить в тех примерах bufferLenght на x, то смысл функции GetNormalizedBufferLength будет ускользать.


s> Ну и не будете же вы для каждого if-а плодить GetSomething(x)? Мне тут лично max кажется более уместным, т.к. что делает max мы можем догадаться, а что подразумевается под NormalizedBufferLength — тут нужны экстрасенсы.

Ну вот примерчик, какого либо выражения.
x = Max(Max(acd,0) + 2, Min(GetX() + wsa * 3 / 8, GetAbc(1,2,3,4,5)))
И возможной записи
x = Max(GetWeight1(),GetWeight2())
Не знаю как вам, но мне больше по душе второе.
s> Так, если привести постороннего человека, то вряд ли он угадает что под нормализованной длиной буфера подразумевается неотрицательная.
Не нужно догадываться, можно глянуть описание или код при необходимости. Я просто сразу вижу — происходит что то с размером, он каким либо образом меняется. Обычно на первом этапе просмотра этого достаточно.

s> s>> Это субъективное наблюдение


s> AN>Я не проводил научных исследований, но мне лично обратное еще не встречалось.


s> Мне встречалось.

Именно в качестве преобладающего использования или просто попадалось?

s> s>> Случай, когда объяснятель и объясняемый близки к средней температуре по больнице, не интересен. Они друг дружке что-то принципиально новое вряд ли объяснят.


s> AN>Ну отчего же? Вы разрабатывали подсистему А, я подсистему Б. Объяснения друг другу будут весьма полезны. А объяснять работу подсистемы А дежурному сантехнику не будет иметь большого смысла.


s> Вы не пытались объяснить смысл алгоритма Дейкстры (например) программисту, совершенно незнакомому с теорией графов?

Т.е этот случай должен быть неинтересен, так как "Они друг дружке что-то принципиально новое вряд ли объяснят."
s> s>> По поводу того же await — мне будет проще почитать в паре-тройке мест, что он значит и потом понимать его в 20и местах использования, чем в 20 местах вчитываться в нагромождение очевидных конструкций.

s> AN>Я привел только пример, что было понятно, что я имею в виду. Но с другой стороны, эти 20 мест уже могут жить в коде лет этак 5 и каждый знает их почти наизусть.

s> AN>Как я уже говорил, конкретная ситуация может быть самая разная. Да и включение чего
s> AN>то нового должно быть "официально одобрено". Если "я нашел" этот await вчера, то это не значит, что я его имею право его использовать уже завтра сразу в проекте.

s> ну фиг с ним с await. Некоторые до сих пор находят для себя yield return. Значит ли это что его нельзя использовать сразу в проекте? И у вас что, есть перечень конструкций, которые можно/нельзя использовать в проекте?

Да есть, и довольно обширный (как раз все что не попало в стандарт 2.0). Изменить довольно затруднительно, по различным причинам.
s> У меня есть обратный пример, когда проект был скован .net 2.0 спустя пару лет после выхода 3.5. Когда я протащил в проект linq (сваял аналог linqbridge), команда сначала отнеслась без этнузиазма, но спустя пару недель начали продуктивно применять.
Вполне могу это понять, но для этого нужно вначале убедить большинство команды в ее полезности и изменить правила. Иначе получится полный бардак, я хочу добавить А, другой Б, третий С и так каждый месяц.
s> s>> Я-то его не видел. Я просто реагирую на "10и страничный свитч" и представляю себе такого нормального монстрика с вложенными свитчами, goto и всякой прелестью, что является вполне типично для 2х и более страничных свитчей, выходящих из под топора среднеотраслевых мастеров.

s> AN>Видите, а мне описанный Вами свитч тяжело представить

s> AN>Еще не встречал фирмы где goto был бы разрешен.

s> А я 8 лет проработал в конторе, где его до сих пор предпочитают другим способам переходов.

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

s> s>> Думать можно разными путями, а уж недумая —


s> AN>Это довольно просто.

s> AN>Предположим, я или скажу
s> AN>"В темной темнице красны девицы.
s> AN>Без нитки, без спицы вяжут вязеницы"
s> AN>или просто покажу картинку.
s> AN>Что быстрее доведет до цели, о чем это я?

s>

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

Так что быстрее? Думать или не думать


s> s>> Мне кажется что у нас с вами разные отладчики. Не приходилось сталкиваться с описанными проблемами. И стек мне видно и Step Into входит в куда надо и брекпоинты ставятся, и место инициализации находится хоть средой хоть рефлектором за секунды. Такое ощущение, что вы отлаживаетесь по твердой копии исходников...


s> AN>Я думаю, что мы просто разные проекты делаем. Вот например, примерчик из здешнего проекта Janus, найдите любым из перечисленных вами способов откуда вызывается данная функция


s> Если честно — лень даже скачивать.

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

s> AN>Теперь поставьте точку останова на функцию AddFolder и покажите на стеке вызов из ProcessMessageKey, да, и потом поставьте уже на данной строке точку останова и при помощи Step Into зайдите в функцию AddFolder.

s> AN>
s> AN>  methodInfo.Invoke(target, null);
s> AN>

s> AN>Просто как некоторый пример, о чем я вёл речь.

s> На сколько я понимаю в этих корках от апельсинов — проблема вовсе не в выпендреже, а в вызове через MethodInfo.Invoke. Если создать Action из methodInfo, а потом вызвать его, то будет и стек и StepInto, и девченки.

А каким образом "убрать" Invoke или если я запускаю Thread в одном месте, а он вызывает функцию из другого места?
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[68]: Как не надо писать код
От: AlexNek  
Дата: 30.04.11 22:46
Оценка:
Здравствуйте, samius, Вы писали:
...
спасибо за ответ, но есть большая вероятность того что в ближайшие пару дней мне не удастся ответить, так что звиняйте если что.
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[4]: Как не надо писать код
От: Sealcon190 Соломоновы острова  
Дата: 05.05.11 07:51
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Я не понимаю, о какой работоспособности можно говорить в коде, где кто-то присылает массив длинной 10 и просит отправить 15 байт.


В фирмваре такое сплошь и рядом. Например, речь идёт о неком железе, запись на которое может происходить только кусками, кратными размеру страницы.
Re: Как не надо писать код
От: Bandy11 Россия  
Дата: 05.05.11 17:29
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


По мне код надо писать как можно проще, без наворотов, — потому что когда приходится
вносить добавления (исправления) через 5-10 лет (как мне) – уже самому приходится вспоминать – и что же этот кусок делает?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Как не надо писать код
От: Bandy11 Россия  
Дата: 05.05.11 17:29
Оценка:
Здравствуйте, xobotik, Вы писали:

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

X>
X>if (buffer != null)
X>

X>Порадовало такое ощущение что код писал параноик)

От многих привычек не так-то и просто избавиться.
Например: на М220 сравнение I=3 никогда не сработает т.к. в целой переменной I не 3 а
2,(9) приходилось добавлять дельту, и при переходе на ЕСку первое время делал также.
А на ЕСке — при записи на винчестер не было никакой гарантии что, данные файла, записались нормально
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[2]: Как не надо писать код
От: Ночной Смотрящий Россия  
Дата: 05.05.11 20:55
Оценка:
Здравствуйте, AlexNek, Вы писали:

AN>Незнаю как вы, но большой одной строки для foreach я как то слабо представляю, поэтому также не смог сразу врубиться, не говоря уж об обилии лямбд


Код вполне очевидный и более менее просто читаемый. Твое плохое знакомство с рядом конструкций C# 3 не делает этот код объективно плохим.
Re[3]: Как не надо писать код
От: Ops Россия  
Дата: 05.05.11 22:15
Оценка:
Здравствуйте, AlexNek, Вы писали:

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


FRE>> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


FRE>> 25 см?

AN>Ну если это код, то я зелёный

Ты зеленый, а у меня 26.
Переубедить Вас, к сожалению, мне не удастся, поэтому сразу перейду к оскорблениям.
Re[5]: Как не надо писать код
От: Sinclair Россия https://github.com/evilguest/
Дата: 06.05.11 00:49
Оценка:
Здравствуйте, Sealcon190, Вы писали:

S>В фирмваре такое сплошь и рядом. Например, речь идёт о неком железе, запись на которое может происходить только кусками, кратными размеру страницы.

Хороший поинт. Но по коду примера этого не видно: по факту функция в данном случае отправит 11 байт (префикс+10 байт), никак не ругаясь.
То, о чём вы говорите, должно работать совершенно наоборот: пользователь отправляет те данные, которые ему нужны, а уже функция взаимодействия с фирмварью обеспечивает выравнивание.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[4]: Как не надо писать код
От: Andy77 Ниоткуда  
Дата: 06.05.11 02:39
Оценка:
Здравствуйте, Sinix, Вы писали:

S>1. warning CS3001: Argument type 'uint' is not CLS-compliant

S>2. а собсно зачем заводить массив, который займёт >2гб памяти? (берём крайний случай — с byte[]/bool[].) В типовой системе из-за фрагментации легко получить OutOfMemory даже на 200мб.

Как это зачем? Мне, например, совсем не помешало бы, объемы данных у нас бывают очень большие. Или "64КБ достаточно для всех"?
Re[8]: Как не надо писать код
От: Andy77 Ниоткуда  
Дата: 06.05.11 02:48
Оценка:
Здравствуйте, Sinix, Вы писали:

K>>Дык уже У массивов есть LongLength

S>
S>Оно есть начиная с .NET 1.1. Позор на мою неседую голову, что ещё сказать.

Есть-то оно есть, но во всех интерфейсах коллекций используется int.
Re[5]: Как не надо писать код
От: Sinix  
Дата: 06.05.11 04:35
Оценка:
Здравствуйте, Andy77, Вы писали:

A>Как это зачем? Мне, например, совсем не помешало бы, объемы данных у нас бывают очень большие. Или "64КБ достаточно для всех"?


Нет конечно. просто шансов, что такой софт регулярно будет падать с out of memory >> 99%.

Ну, и если реально надо — или перелазить на unmanaged, или глядеть в сторону готовых решений — например,
http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx
Re[2]: Как не надо писать код
От: sidorov18 США  
Дата: 06.05.11 08:45
Оценка:
Здравствуйте, xobotik, Вы писали:

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

X>
X>if (buffer != null)
X>

X>Порадовало такое ощущение что код писал параноик)

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

В с++ на такое обычно пишутся ассерты.
Re[4]: Как не надо писать код
От: AlexNek  
Дата: 06.05.11 15:43
Оценка:
Здравствуйте, Ops, Вы писали:

Ops> AN>Здравствуйте, _FRED_, Вы писали:


Ops> FRE>> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


Ops> FRE>> 25 см?


Ops> AN>Ну если это код, то я зелёный


Ops> Ты зеленый, а у меня 26.


А дело разве в длине? Да и жалко что вместо Петра 1, не была особа женского пола, хоть вагоны не нужно было переставлять
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[3]: Как не надо писать код
От: AlexNek  
Дата: 06.05.11 15:43
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС> AN>Незнаю как вы, но большой одной строки для foreach я как то слабо представляю, поэтому также не смог сразу врубиться, не говоря уж об обилии лямбд


НС> Код вполне очевидный и более менее просто читаемый. Твое плохое знакомство с рядом конструкций C# 3 не делает этот код объективно плохим.


а где там конструкции C# 3 или мы о разном коде говорим?
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[2]: Как не надо писать код
От: AlexNek  
Дата: 06.05.11 15:43
Оценка:
Здравствуйте, Bandy11, Вы писали:

B> AN>Что то часто мне стал попадаться код в который сразу не врубишься, при этом код делает свою задачу правильно. Предлагаю постить сюда ваши образчики и комментарии.


B> По мне код надо писать как можно проще, без наворотов, — потому что когда приходится

B> вносить добавления (исправления) через 5-10 лет (как мне) – уже самому приходится вспоминать – и что же этот кусок делает?
совершенно согласен
avalon 1.0rc3 rev 419, zlib 1.2.3
Re[6]: Как не надо писать код
От: Sealcon190 Соломоновы острова  
Дата: 07.05.11 13:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Хороший поинт. Но по коду примера этого не видно: по факту функция в данном случае отправит 11 байт (префикс+10 байт), никак не ругаясь.


Согласен. Я всего лишь отметил излишне обобщённое высказывание.
Re[6]: Как не надо писать код
От: Andy77 Ниоткуда  
Дата: 10.05.11 20:45
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Нет конечно. просто шансов, что такой софт регулярно будет падать с out of memory >> 99%.


Намного больше 99% — это сколько? И откуда такой вывод? Памяти нынче много, про характер софта тебе ничего не известно.

S>Ну, и если реально надо — или перелазить на unmanaged, или глядеть в сторону готовых решений — например,

S>http://blogs.msdn.com/b/joshwil/archive/2005/08/10/450202.aspx

Мы в некотором роде как раз и разрабатываем "готовые решения". Понятно, что существуют обходные пути, но всё это напоминает мучения с моделями памяти 8086
Re[7]: Как не надо писать код
От: Sinix  
Дата: 11.05.11 00:19
Оценка:
Здравствуйте, Andy77, Вы писали:

A>Намного больше 99% — это сколько? И откуда такой вывод? Памяти нынче много, про характер софта тебе ничего не известно.

Все 200 Максимальный размер объекта в .Net — 2гб. Кстати, мы ведь обсуждаем только решения под x64?

A>Мы в некотором роде как раз и разрабатываем "готовые решения". Понятно, что существуют обходные пути, но всё это напоминает мучения с моделями памяти 8086


Так способов куча — BigArray, MMF, аллокация в нативной куче... Всё не подходит?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.