Re[6]: Вариант 0K
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 01.09.10 19:47
Оценка: 8 (1)
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>Это мне вопрос? Я скопипастил.


0K>Вы же переделали. НЕ пытайтесь избежать ответственности за свой код.


Вот тут
Автор: gandjustas
Дата: 20.08.10
я описал функцию, которая увеличивает значение счетчика в файле, использую её для реализации.

using System;
using System.Diagnostics.Contracts;
using System.IO;
using System.Text.RegularExpressions;

public class Program
{
    //Изменение счетчика
    static void Increment(string fileName)
    {
        Contract.Requires(fileName != null);
        Contract.Requires(fileName != string.Empty);

        using (var f = File.Open(fileName, FileMode.OpenOrCreate))
        {
            var reader = new StreamReader(f);
            var content = reader.ReadToEnd();

            var counter = 0;
            if (int.TryParse(content, out counter))
            {
                counter = (counter == int.MaxValue) ? 0 : (counter + 1);
            }

            f.Seek(0, SeekOrigin.Begin);
            f.SetLength(0);

            var writer = new StreamWriter(f);
            writer.Write(counter);
        }
    }

    //Любая обработка ошибок
    static bool HandleException(Exception e)
    {
        
        Contract.Requires(e != null);

        if (e is PathTooLongException
        || e is UnauthorizedAccessException
        || e is DirectoryNotFoundException
        || e is IOException)
        {
            Console.WriteLine("Операция завершилась неуспешно. Ниже приведено полное описание ошибки.");
            Console.WriteLine(e);
            return true;
        }
        return false;
    }

    //Один цикл пользовательского ввода
    static void UiCycle()
    {
        Console.WriteLine("Введите имя счетчика:");
        string alias = Console.ReadLine();

        //Проверку по вкусу
        if (!Regex.IsMatch(alias, "[a-z]+")) 
        {
            Console.WriteLine("Некорректное имя счетчика (пояснение каким должно быть правильное имя).");
        }
        Contract.Assume(alias != null);
        Contract.Assume(alias != string.Empty);

        Increment(alias);

        Console.WriteLine("Операция успешно завершена.");
    }

    static void Main(string[] args)
    {
        const string YES_SYMBOLS = "YyДд";

        while (true)
        {
            try
            {
                UiCycle();
            }
            catch (Exception e)
            {
                if (!HandleException(e))
                    throw;
            }

            Console.WriteLine("Повторить?");

            if (!YES_SYMBOLS.Contains(Console.ReadLine()))
                break;

            Console.Clear();
        }
    }
}

Получилось в два раза короче чем твой вариант.

Что я хочу показать этим кодом:
1)Если исключение ожидаемо и можно как-то исправить ситуацию, то можно обойтись без исключений (не всегда верно, но по возможности лучше делать так)
2)Unhandled exception policy aka политика обработки неперехваченных исключений должна быть отделена от основной логики, а еще желательно реюзабельна (это отлично достигается с помощью соответствующих средств)
3)Показ сообщения пользователю вполне возможно выполнять без исключений и стоит именно так делать.
4)Операция (или вся программа) должна прерываться при возникновении неперехваченного исключения. Код обработки таких исключений должен быть вне операции.
Re[7]: Критика варианта gandjustas
От: 0K Ниоткуда  
Дата: 05.09.10 17:02
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Получилось в два раза короче чем твой вариант.


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

1. Проверка имени счетчика у вас вынесена в Presentation Layer. Тот, кто использует библиотеку должен знать низкоуровневые детали. Опять-же, если вы измените тип хранилища в своей библиотеке -- прийдется изменять и весь код который библиотеку использует.
2. Контракты вы, видимо, только начинаете использовать. Вы хоть программу то свою запускали?

//Проверку по вкусу
if (!Regex.IsMatch(alias, "[a-z]+")) 
{
      Console.WriteLine("Некорректное имя счетчика (пояснение каким должно быть правильное имя).");
}


Заметили, что если имя счетчика некорректно -- программа продолжит работу с некорректным именем счетчика? Даже никто не исправил пока меня не было.

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

G>Что я хочу показать этим кодом:

G>1)Если исключение ожидаемо и можно как-то исправить ситуацию, то можно обойтись без исключений (не всегда верно, но по возможности лучше делать так)

В таком случае лучше применить паттерн TryParse, а не то что вы сделали -- вынесли логику в Presentation Layer.

G>3)Показ сообщения пользователю вполне возможно выполнять без исключений и стоит именно так делать.


В простейшем случае (как у меня в примере с именем счетчика -- посмотрите как правильно) -- да. А вот в более сложных случаях -- нужно обязательно вывести конкретизирующую информацию.
=сначала спроси у GPT=
Re[8]: Критика варианта gandjustas
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 05.09.10 21:08
Оценка: :)
Здравствуйте, 0K, Вы писали:

0K>Здравствуйте, gandjustas, Вы писали:


G>>Получилось в два раза короче чем твой вариант.


0K>Ну наконец то вы написали свой вариант. Давайте теперь размебем ваши ошибки (то что он короче -- не показатель, главное качество кода а не его коротковизна).



0K>1. Проверка имени счетчика у вас вынесена в Presentation Layer.

Правильно, потому что PL отвечает за преобразование имени счетчика в имя файла.

0K>Тот, кто использует библиотеку должен знать низкоуровневые детали.

Я про библиотеку писал выше. Да — вызывающий код должен знать что делает функция Increment, и даже то что она работает с файлами. Это знание кстати передается в названии параметра.

0K>Опять-же, если вы измените тип хранилища в своей библиотеке -- прийдется изменять и весь код который библиотеку использует.

Если я изменю тип хранилища — я напишу новую функцию.

0K>2. Контракты вы, видимо, только начинаете использовать.

Ниугадал.

0K>Вы хоть программу то свою запускали?

Не-а

0K>
0K>//Проверку по вкусу
0K>if (!Regex.IsMatch(alias, "[a-z]+")) 
0K>{
0K>      Console.WriteLine("Некорректное имя счетчика (пояснение каким должно быть правильное имя).");
0K>}
0K>

return забыл.

0K>Заметили, что если имя счетчика некорректно -- программа продолжит работу с некорректным именем счетчика? Даже никто не исправил пока меня не было.

Видимо никто не запускал

0K>3. При возникновении ошибки вы не даете возможности пользователю самому понять что произошло. Текст ошибки для пользователя все время одинаковый.

Нет, он выводится вместе с exception, который содержит локализованный текст ошибки. Также выводится stacktrace, что позволяет программисту определить где была проблема.
Кроме того я сделал пометку, что можно написать любые сообщения об ошибках в коде HandleException, не затрагивая всю остальную логику.

0K>Для вас все пользователи -- дураки. А на самом деле дураком окажется тот, кто таковыми считает пользователей -- они будут звонить вам и вы как дурак будете тратить время на их глупые вопросы. Дайте возможность пользователю самому понять что произошло.

См выше.

Вообще это имеет смысл если пользователь сможет сам исправить ситуацию. А исправить он вероятнее всего сможет в случае UnauthorizedAccessException и DirectoryNotFoundException, и то не факт.


G>>Что я хочу показать этим кодом:

G>>1)Если исключение ожидаемо и можно как-то исправить ситуацию, то можно обойтись без исключений (не всегда верно, но по возможности лучше делать так)

0K>В таком случае лучше применить паттерн TryParse

Я применил как раз TryParse, там где исключение ожидаемо и исправимо.

0K>а не то что вы сделали -- вынесли логику в Presentation Layer.

Это ты о чем?

G>>3)Показ сообщения пользователю вполне возможно выполнять без исключений и стоит именно так делать.

0K>В простейшем случае (как у меня в примере с именем счетчика -- посмотрите как правильно) -- да. А вот в более сложных случаях -- нужно обязательно вывести конкретизирующую информацию.
Ну поменяй HandleException и выводи. Ты все еще не понял что:
а)Для вывода конкретизирующей информации в 99,9% случаев не нужны исключения
б)Сам вывод сообщений не касается основной логики работы.

У меня нету цели написать программу, которая работает как ты хочешь. Как минимум потому что я не знаю как ты хочешь чтобы она работала.
Я показываю несостоятельность твоей концепции о различных видах исключений и их применимости, а также показываю как надо писать обработку исключений в большинстве случаев.
Re[4]: Конкурс на умение работать с Exception
От: andy1618 Россия  
Дата: 08.09.10 23:38
Оценка: 1 (1)
Здравствуйте, Neco, Вы писали:

N>
...
N>        public Result PerformIncrement() {
N>            CreateFileIfItDoesNotExist();
N>            var oldValue = ReadCurrentValue();
N>            var newValue = oldValue + 1;
N>            WriteNewValue(newValue);
N>            return new Result(oldValue, newValue);
N>        }
...

N>

Строчку "var newValue = oldValue + 1;" неплохо бы в блок "checked{}" обрамить, чтобы при переполнении генерировалось исключение.
А то какой-нибудь миллиардер при попытке добавить доллар к своему состоянию в 2147483647 баксов, после выполнения программы расстроится, т.к. его счёт молча уйдёт в глубокие минусА
Re[5]: Конкурс на умение работать с Exception
От: Neco  
Дата: 09.09.10 05:12
Оценка:
Здравствуйте, andy1618, Вы писали:

A>Строчку "var newValue = oldValue + 1;" неплохо бы в блок "checked{}" обрамить, чтобы при переполнении генерировалось исключение.

A>А то какой-нибудь миллиардер при попытке добавить доллар к своему состоянию в 2147483647 баксов, после выполнения программы расстроится, т.к. его счёт молча уйдёт в глубокие минусА
а у меня в проекте стоит :P

а если по-честному — сравнительно недавно узнал про эту заморочку с непроверяемыми переполнениями. ещё не выработал привычку думать об этом. спасибо за замечание!

а вы сами как — в проекте ставите или каждый раз checked используете?
всю ночь не ем, весь день не сплю — устаю
Re[6]: Конкурс на умение работать с Exception
От: andy1618 Россия  
Дата: 09.09.10 05:59
Оценка:
Здравствуйте, Neco, Вы писали:

N>а у меня в проекте стоит :P





N>а если по-честному — сравнительно недавно узнал про эту заморочку с непроверяемыми переполнениями. ещё не выработал привычку думать об этом. спасибо за замечание!


В этом смысле хорош РEX: выявление переполнений — его конёк! ))


N>а вы сами как — в проекте ставите или каждый раз checked используете?


На проект надежды мало, т.к. код могут при рефакторинге перенести куда-нибудь в другое место.
Обычно делаем так: после написания класса на него пишется юнит-тест, где проверяются граничные значения. Потом смотрим на упавшие тесты — в подавляющем большинстве случаев можно вообще избежать переполнений, применив правильные типы данных. Вот, кстати, поучительный прошлогодний пример: здесь
Автор: andy1618
Дата: 20.02.09
.

Ну а там, где переполнения всё-таки возможны и критичны, ставим checked.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.